2010-09-04 4 views
6

Только после того, как некоторые мнения по лучшим способом для достижения следующих результатов:MySQL - как оптимизировать запрос для подсчета голосов

Я хотел бы хранить в своих продуктах баз данных MySQL, которые могут быть голосовавших на пользователей (каждый голос стоит +1). Я также хочу видеть, сколько раз всего голосовал пользователь.

К моему простому виду, следующая структура таблицы будет идеальным:

table: product   table: user   table: user_product_vote  
+----+-------------+ +----+-------------+ +----+------------+---------+ 
| id | product | | id | username | | id | product_id | user_id | 
+----+-------------+ +----+-------------+ +----+------------+---------+ 
| 1 | bananas  | | 1 | matthew  | | 1 | 1   | 2  | 
| 2 | apples  | | 2 | mark  | | 2 | 2   | 2  | 
| .. | ..   | | .. | ..   | | .. | ..   | ..  | 

Таким образом, я могу сделать COUNT таблицы user_product_vote для каждого продукта или пользователя.

Например, когда я хочу посмотреть бананы и количество голосов, чтобы показать на веб-странице я мог бы выполнить следующий запрос:

SELECT p.product AS product, COUNT(v.id) as votes 
FROM product p 
LEFT JOIN user_product_vote v ON p.id = v.product_id 
WHERE p.id =1 

Если мой сайт стал чрезвычайно успешным (мы можем все мечты), и у меня было тысячи пользователей, голосовавших по тысячам продуктов, я опасаюсь, что выполнение такого COUNT с каждым просмотром страницы будет крайне неэффективным с точки зрения ресурсов сервера.

Более простым подходом было бы иметь столбец «голосов» в таблице продуктов, который увеличивается каждый раз при добавлении голоса.

table: product    
+----+-------------+-------+ 
| id | product | votes | 
+----+-------------+-------+ 
| 1 | bananas  | 2  | 
| 2 | apples  | 5  | 
| .. | ..   | .. | 

Хотя это более рациональное использование ресурсов - я теряю данные (например, я больше не могу помешать человеку дважды голосовать, поскольку нет никаких сведений об их деятельности для голосования.).

Мои вопросы:
i) Я слишком беспокоюсь о ресурсах сервера и должен просто придерживаться трехфазной опции? (т. е. мне нужно больше верить в способность базы данных обрабатывать большие запросы)
ii) является их более эффективным способом достижения результата без потери информации

+1

еще одна проблема, с которой у вас есть, вероятно, у вас никогда не было веб-сайта, который получает массовый трафик, поэтому вы не уверены в возможностях php/mysql. Я заверяю вас, что mysql может обрабатывать тысячи запросов в секунду с понижающейся производительностью – RobertPitt

ответ

6

Вы никогда не можете беспокоиться о ресурсах, когда вы начинаете создавать приложение, у вас всегда должны быть ресурсы, пространство, скорость и т. Д., Если трафик вашего сайта резко возрастает, и вы никогда не строили ресурсы, тогда вы начинаете получать в проблемы.

Что касается системы голосования, лично я буду держать голоса так:

table: product   table: user    table: user_product_vote  
+----+-------------+ +----+-------------+ +----+------------+---------+ 
| id | product | | id | username | | id | product_id | user_id | 
+----+-------------+ +----+-------------+ +----+------------+---------+ 
| 1 | bananas  | | 1 | matthew  | | 1 | 1   | 2  | 
| 2 | apples  | | 2 | mark  | | 2 | 2   | 2  | 
| .. | ..   | | .. | ..   | | .. | ..   | ..  | 

Причины:

Во-первых user_product_vote не содержит текста, капли и т.д., это чисто целое число, так что занимает меньше ресурсов в любом случае.

Во-вторых, у Вас есть больше дверного проема новых объектов в рамках приложения, такие как Всего голосов последние 24 часа, самым высоким рейтингом продукт в течение последних 24 часов и т.д.

Возьмите этот пример, например:

table: user_product_vote  
+----+------------+---------+-----------+------+ 
| id | product_id | user_id | vote_type | time | 
+----+------------+---------+-----------+------+ 
| 1 | 1   | 2  | product |224.. | 
| 2 | 2   | 2  | page  |218.. | 
| .. | ..   | ..  | ..  | .. | 

и простой запрос:

SELECT COUNT(id) as total FROM user_product_vote WHERE vote_type = 'product' AND time BETWEEN(....) ORDER BY time DESC LIMIT 20 

Другое дело, если пользователь проголосовал на 1AM, а затем снова попытался голосовать в 2PM, вы можете легко проверить, когда последний раз они голосовали, и если им разрешено голосовать снова.

Есть так много возможностей, которые вам не хватает, если вы будете придерживаться своего инкрементного примера.


В отношении вашего count(), независимо от того, сколько вам оптимизировать ваши запросы не будет действительно сделать разницу в крупном масштабе.

С чрезвычайно большой пользовательской базой ваше использование ресурсов будет рассмотрено с другой точки зрения, например балансировщики нагрузки, в основном настройки сервера, Apache, ловушка и т. Д., Только с вашими запросами вы можете только так много сделать.

0

Вы должны сбалансировать желание своих (в котором лучше всего использовать вторую схему) и возможность подсчета голосов для определенных пользователей и предотвращения двойного голосования (для чего я бы выбрал первую схему). Поскольку вы используете только целые столбцы для таблицы user_product_vote, я не вижу, как производительность может сильно пострадать. Отношения «многие ко многим» являются общими, поскольку вы реализовали с помощью user_product_vote. Если вы хотите подсчитать голоса для конкретных пользователей и предотвратить двойное голосование, user_product_vote - это единственный способ, который я могу придумать для его реализации, так как любой другой может привести к разреженным записям, дублированию записей и т. Д.

1

Почему бы не смешать и не сопоставить оба? Просто получите окончательный счет в таблицах продуктов и пользователей, чтобы вам не приходилось подсчитывать каждый раз и иметь таблицу голосов, чтобы не было двойной публикации.

Редактировать: Чтобы объяснить это немного дальше, таблица продуктов и пользователей будет иметь столбец с названием «голосов». Каждый раз, когда вставка успешно выполняется в user_product_vote, увеличивайте соответствующие записи пользователей и продуктов. Это позволило бы избежать повторных голосований, и вам также не придется запускать сложный счетный запрос каждый раз.

Редактировать: Также я предполагаю, что вы создали уникальный индекс для product_id и user_id, в этом случае любая попытка дублирования автоматически завершится неудачно, и вам не придется проверять таблицу перед вставкой. Вы просто должны убедиться, что запрос вставки запущен, и вы получили действительное значение для «id» в форме на insert_id

0

Вы не хотите обновлять таблицу продуктов напрямую с помощью агрегата каждый раз, когда кто-то голосует - это будет блокировать строки продуктов, которые затем будут влиять на другие запросы, которые используют продукты.

Предполагая, что не все запросы продукта должны включать в себя столбец голосов, вы можете сохранить отдельную таблицу продуктов, которая сохранит текущие итоговые значения, и сохранить таблицу userproductvote в качестве средства для принудительного использования вашего голосования пользователей в соответствии с бизнес-правилами продукта и/или аудит.

2

Если мой сайт стал чрезвычайно успешным (мы можем все мечтаем), и я тысячи пользователей, голосовавших на тысячи продуктов, я боюсь, что выполнение такой COUNT с каждым видом страницы будет крайне неэффективным с точки зрения ресурсов сервера ,

Не тратьте время на решение мнимых проблем. mysql отлично умеет обрабатывать тысячи записей за доли секунды - для этого нужны базы данных. Чистая и простая база данных и структура кода гораздо важнее мифической «оптимизации», которой никто не нуждается.

Смежные вопросы