Эффективное получение для системы голосования в PHP и MySQL

У меня есть система, в которой зарегистрированные пользователи могут проголосовать за/голосовать за комментарии. Он очень похож на систему голосования Stack Overflow.

Я сохраняю голоса в таблице со значениями как таковыми:

vote_id | vote_comment_id | vote_user_id | vote_date | vote_type 

Теперь у меня есть несколько вопросов относительно скорости и эффективности для следующего:

ПРОБЛЕМА:. Когда пользователь открывает страницу с комментариями, мне нужно, если этот пользователь уже проголосовал за UP/DOWN за комментарий, чтобы показать его; "вы голосовали" или "вы проголосовали" рядом с комментарием (в Qaru выделено изображение для голосования).

МОЙ ВОЗМОЖНОЕ РЕШЕНИЕ:. Сейчас, когда я открываю страницу с картинками, я просматриваю каждый комментарий и прохожу через мою таблицу голосов, а также проверяю, проголосовал ли пользователь и показ статуса ( Я сравниваю vote_user_id с сеансом пользователя).

Насколько это эффективно? У кого-нибудь есть лучший подход к решению этой проблемы?

Ответ 1

Вы просматриваете таблицу голосов? Вы читаете всю базу данных в памяти, а затем перебираете ее?

Вы пытались запросить базу данных только для соответствующих данных?

SELECT vote_comment_id, vote_type
FROM vote
WHERE vote_user_id = 34513
  AND vote_comment_id IN (3443145, 3443256, 3443983)

Ответ 2

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

поэтому вместо того, чтобы перебирать всю таблицу голосов, вы можете сделать что-то вроде

select vote_type from vote_table where vote_comment_id = $commentId and vote_user_id = $userId

или даже лучше, когда вы извлекаете фактические комментарии, вы можете сделать left join так:

select c.*, v.vote_type from comments c left join (select * from votes where vote_user_id = $userId) v on v.vote_comment_id = c.comment_id

то проверьте, является ли параметр vote_type нулевым, вверх или вниз в вашем цикле отображения. это может быть менее эффективным, если у вас есть 1000 комментариев и показывается только 10 за раз, но в этом случае первый способ должен помочь.

[отредактирован после комментария выше о столбце vote_type]

Ответ 3

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

select c.*, v.vote_type 
from comments c 
left join vote v 
on v.vote_comment_id = c.comment_id
and v.vote_user_id = $userId

Использование оператора CASE для отображения/скрытия параметра vote_type.

select c.*, CASE v.vote_user_id WHEN $userId
THEN v.vote_type /*compare vote_user_id with the user session*/
ELSE null END AS 'votetype' /*hide vote_type */
from comments c 
left join vote v 
on v.vote_comment_id = c.comment_id

Ответ 4

Вам не нужен столбец, за который он голосовал, т.е. post_id?

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


Собственно, я только заметил, что vote_comment_id - это не то, что я читал (vote_comment).

Вам просто нужно проверить, существует ли строка

Ответ 5

У меня есть сайт с аналогичной логикой. Я не отслеживаю индивидуальные голоса (для этого), у меня есть только таблица сообщений (изображений), с подсчетом голосов и текстовым полем с идентификатором пользователя: vote; userid: vote... pairs, где голосом является +/-. Таким образом, мне не нужно выбирать из огромной таблицы голосов, и мне все равно нужно загрузить строку, принадлежащую сообщению. Простой поиск строки для "userid:" покажет, проголосовал ли текущий пользователь или нет.

Операции ACID необходимы для постоянного согласования количества голосов и текстового поля голосов.

Ответ 6

Мое решение состоит в том, чтобы получать все голоса пользователей при входе в сеанс. Извлеките все идентификаторы комментариев в два массива:

$_SESSION['votes'] = array(
    'up'   => array(12, 854, 87, 78),
    'down' => array(84, 32, 77)
);

и когда пользователь получает доступ к некоторой странице, проверьте, существует ли ее идентификатор в любом из этих массивов.