Эффективное получение для системы голосования в 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)
);
и когда пользователь получает доступ к некоторой странице, проверьте, существует ли ее идентификатор в любом из этих массивов.