Сохранение "голосов" в базе данных
Я пишу, что будет приложением для интрасети, и одна из его функций примерно аналогична голосованию по содержанию - в отличие от того, что делают SO, Amazon и многие другие сайты.
Предполагая, что каждый элемент, имеющий право голоса, имеет уникальный идентификатор, и каждый пользователь (он аутентифицирован) имеет уникальный идентификатор, самый простой способ - иметь таблицу "голосов"...
ContentID int
UserID int
VoteValue int
Но это создает одну строку за голос - с миллионами контента и десятками тысяч пользователей, эта таблица будет огромной огромной. Это лучший способ сделать это? Я имею в виду, если int принимает 4 байта, каждая строка принимает 12 байтов. Если миллион штук контента получит сто голосов, то 400 МБ + на складе, да? Кажется... как много:). Даже если VoteValue является tinyint (что, вероятно, хорошо) и только 1 байт, это еще пара сотен мегабайт в таблице. Я имею в виду sheesh.
Есть ли более разумный способ? Должен ли я хранить эту таблицу "голосов" в отдельной базе данных (игнорируя потенциальные проблемы с целостностью данных), чтобы разделить ее на "основные" данные с точки зрения хранения и производительности?
(Я понимаю, что в сегодняшнем мире 400MB не тонна, но похоже, что LOT просто хранит голоса, да?)
Ответы
Ответ 1
Лично, пока у вас есть хорошие индексы на месте, вы делаете это правильно. В зависимости от вашего использования, для производительности вы можете попытаться избежать попадания в таблицу голосов, сохранив информацию вторичного счета, но в целом, если вы должны отслеживать, что ВОЗ проголосовала за что-то, вам нужно сделать это так, как вы указали.
Я бы не стал переезжать в другую базу данных, если вы действительно обращаете внимание на SQL Server, вы можете создать отдельную файловую группу, чтобы ее удержать..... но, скорее всего, не нужно.
Ответ 2
Ну, да, но вам нужно посмотреть на большую картину. С миллионами СОДЕРЖАНИЙ:
(Размер содержимого) → (Размер голосов): где " → " означает "намного больше".
Если у вас есть миллион частей контента, то это может быть терабайт данных, где в качестве голосов 400 МБ. Большая часть права?
Я бы также добавил, если вы беспокоитесь о масштабируемости, посмотрите этот блог:
http://highscalability.com/
Ответ 3
Вероятно, вам также понадобится идентификатор автора содержимого в таблице, чтобы упростить обнаружение нарушений в голосовании. (Да, это, по-видимому, избыточная информация. Альтернативно регулярно создается сводная таблица, чтобы узнать, кто голосует за кого.)
Для чего это стоит, таблица голосования 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-адрес.)
Ответ 4
Если вам нужно отслеживать, проголосовал ли пользователь за конкретный элемент, и если существуют разные значения голоса (например, от 1 звезды до 5 звезд), то это примерно так же компактно, как и получается.
Не забывайте, что для разумных скоростей доступа вам нужно будет индексировать данные (два индекса, возможно - один с ContentID в качестве ведущего столбца, один с идентификатором пользователя в качестве ведущего столбца).
Вам нужно будет решить, есть ли причина не хранить таблицу отдельно от других таблиц. То, что это означает, зависит от используемой СУБД - с помощью Informix таблица будет находиться в одной базе данных, но хранится в другом dbspace, и вы можете иметь индексы, хранящиеся в двух других различных доменах.
Ответ 5
Я бы сказал, вам нужно выяснить, как эти голоса будут использоваться и спроектировать конкретные запросы для вашей модели данных. Это не обязательно модель 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 байтами на разделитель id + составляют 500 байтов. В предложенном вами варианте 100 голосов составляют 800 байт.
Отказ от ответственности: я никогда не реализовал ничего подобного, это просто идея.