Я пишу приложение для интрасети, и одна из его функций примерно аналогична голосованию по содержанию - мало чем отличается от того, что делают SO, Amazon и многие другие сайты.
Предполагая, что каждый голосующий фрагмент контента имеет уникальный идентификатор, и каждый пользователь (прошедший проверку подлинности) имеет уникальный идентификатор, самый простой способ - создать таблицу «голосов» ...
ContentID int
UserID int
VoteValue int
Но это создает одну строку для каждого голоса - с миллионами частей контента и десятками тысяч пользователей эта таблица будет огромной огромной. Это лучший способ сделать это? Я имею в виду, что если int занимает 4 байта, каждая строка занимает 12 байтов. Если миллион элементов контента получит сотню голосов, это будет 400 МБ + хранилища, да? Вроде ... много :). Даже если VoteValue представляет собой крошечный интервал (что, вероятно, нормально) и всего 1 байт, это все равно пара сотен мегабайт в таблице. Я имею в виду, черт возьми.
Есть ли способ поумнее? Следует ли мне хранить эту таблицу «голосов» в отдельной базе данных (игнорируя потенциальные проблемы целостности данных), чтобы отделить ее от «основных» данных с точки зрения хранения и производительности?
(Я понимаю, что в сегодняшнем мире 400 МБ - это не тонна, но кажется, что МНОГО просто для хранения голосов, да?)

Лично вы все делаете правильно, пока у вас есть хорошие индексы. В зависимости от вашего использования, для повышения производительности вы можете попытаться избежать попадания в таблицу голосов, сохранив вторичную информацию о подсчете, но в целом, если вы должны отслеживать, кто за что-то проголосовал, вам нужно сделать это так, как вы указали.
Я бы не стал беспокоиться о переходе на другую базу данных, если вы ДЕЙСТВИТЕЛЬНО заинтересованы в SQL Server, вы можете создать отдельную файловую группу для ее хранения… но, скорее всего, в этом нет необходимости.
Что ж, да, но вам нужно взглянуть на картину в целом. С миллионом элементов СОДЕРЖАНИЯ:
(Размер содержания) >> (Размер голосов): где «>>» означает «намного больше».
Если у вас есть миллион частей контента, это может быть терабайт данных, тогда как количество голосов составляет 400 МБ. Большое дело, правда?
Я бы также добавил, что если вас беспокоит масштабируемость, загляните в этот блог:
Если вам нужно отслеживать, проголосовал ли пользователь за конкретный элемент, и если есть разные значения голосов (например, от 1 до 5 звезд), то это примерно так же компактно, как и получается.
Не забывайте, что для разумной скорости доступа вам необходимо проиндексировать данные (возможно, два индекса - один с ContentID в качестве ведущего столбца, другой с идентификатором пользователя в качестве ведущего столбца).
Вам нужно будет решить, есть ли причина не хранить таблицу отдельно от других таблиц. Что это означает, зависит от СУБД, которую вы используете - с Informix таблица будет в той же базе данных, но храниться в другом dbspace, и у вас могут быть индексы, хранящиеся в двух других разных пространствах базы данных.
Возможно, вам также понадобится идентификатор автора содержимого в таблице, чтобы упростить обнаружение злоупотреблений при голосовании. (Да, это, по-видимому, избыточная информация. Альтернативой является регулярное построение сводной таблицы, чтобы видеть, кто за кого голосует.)
Как бы то ни было, таблица голосования perlmonks выглядит так:
`vote_id` int(11) NOT NULL default '0',
`voter_user` int(11) NOT NULL default '0',
`voted_user` int(11) default NULL,
`weight` int(11) NOT NULL default '0',
`votetime` datetime NOT NULL default '0000-00-00 00:00:00',
`ip` varchar(16) default NULL,
PRIMARY KEY (`vote_id`,`voter_user`),
KEY `voter_user_idx` (`voter_user`,`votetime`),
KEY `voted_user_idx` (`voted_user`,`votetime`)
(vote_id - это идентификатор контента, ip - это IP-адрес.)
Я бы сказал, вам нужно выяснить, как эти голоса будут использоваться, и сначала разработать конкретные запросы для вашей модели данных. Это не обязательно модель SQL. Если вы пришли из мира SQL, прохождение официального руководства по MongoDB поможет вам сначала очистить разум.
Например, если вам нужно хранить и отображать голоса только для одной страницы вопроса, может быть удобно хранить голоса в одном строковом поле проблемы, которое будет выглядеть как id1:id2:id3:. Предполагая, что все идентификаторы имеют одинаковую длину, есть несколько интересных свойств:
Подсчитайте все голоса за вопрос:
len(issue.votes)/len(id)
Найти Я голосовал по вопросу
myid in issue.votes
Найдите все вопросы, за которые вы проголосовали:
select issue.id from issues where issue.votes contains(myid)
Найдите наиболее популярные вопросы
select issue.id from issues order by len(issue.votes) desc limit 10
Эта архитектура позволяет избежать дорогостоящих вычислений при чтении в этих конкретных случаях, но обновление issue.votes при голосовании может быть дороже, чем добавление строки в таблицу. В этом случае 100 голосов по 4 байта на идентификатор + разделитель - это строка из 500 байтов. В предложенном вами варианте 100 голосов - это 800 байт.
Отказ от ответственности: я никогда не реализовывал ничего подобного, это просто идея.