Этот код выбора SQL следует хорошей практике? - PullRequest
2 голосов
/ 18 июня 2010

Я использую SQLite и позже перенесу на MySQL (5).

Я хотел знать, что я делаю что-то, чего не должен делать.Я специально попытался спроектировать, поэтому я буду сравнивать с 0 вместо 1 (я изменил hasApproved на NotApproved, чтобы сделать это, ничего страшного, и я не написал никакого кода)Мне сказали, что мне никогда не нужно писать подзапрос, но я делаю здесь.Моя таблица голосов - просто id, ip, postid (я не думаю, что вместо этого могу написать этот подзапрос как объединение?), И это почти все, что у меня на уме.о, так как таблицы создаются с помощью отражения и повсюду.

select 
    id, 
    name, 
    body, 
    upvotes, 
    downvotes, 
    (select 1 from UpVotes where IPAddr=? AND post=Post.id) as myup, 
    (select 1 from DownVotes where IPAddr=@0 AND post=Post.id) as mydown
from Post 
where 
    flag = '0'
limit ?, ?"

Ответы [ 4 ]

1 голос
/ 18 июня 2010

Поскольку вы спрашиваете о передовых методах ... "положительные и отрицательные голоса", появляющиеся в вашей таблице сообщений, выглядят так, как будто вы дублируете данные в своей базе данных.Это проблема, потому что теперь вам всегда нужно беспокоиться о том, являются ли данные синхронизированными и правильными.Если вы хотите узнать количество поднятых голосов, подсчитайте их, не сохраняйте их в таблице Post.Я не уверен, что это то, что вы делаете, но это предположение.

На ваш запрос ... Вы, вероятно, получите лучшую производительность, используя подзапрос JOINed вместо того, как он у вас есть.Со скалярными подзапросами в качестве столбцов их нужно запускать один раз для каждой возвращаемой строки.Это может быть довольно большой удар по производительности, если вы возвращаете кучу строк.Вместо этого попробуйте:

SELECT
    P.id,
    P.name,
    P.body,
    P.upvotes,
    P.downvotes,
    COALESCE(UV.cnt, 0) AS upvotes2,
    COALESCE(DV.cnt, 0) AS downvotes2
FROM
    dbo.Posts P
LEFT OUTER JOIN (SELECT post_id, COUNT(*) cnt FROM dbo.UpVotes GROUP BY post_id) AS UV ON UV.post_id = P.id
LEFT OUTER JOIN (SELECT post_id, COUNT(*) cnt FROM dbo.DownVotes GROUP BY post_id) AS DV ON DV.post_id = P.id

Сравните его с вашим собственным запросом и посмотрите, дает ли он более высокую производительность.

РЕДАКТИРОВАТЬ: Несколько других авторов рекомендовали использовать одну таблицу для увеличения / уменьшения.голосов.Они абсолютно правильны.Это делает запрос еще проще и, вероятно, намного быстрее:

SELECT
    P.id,
    P.name,
    P.body,
    P.upvotes,
    P.downvotes,
    SUM(CASE WHEN V.vote_type = 'UP' THEN 1 ELSE 0 END) AS upvotes2,
    SUM(CASE WHEN V.vote_type = 'DOWN' THEN 1 ELSE 0 END) AS downvotes2,
FROM
    dbo.Posts P
LEFT OUTER JOIN Votes V ON
    V.post_id = P.id
GROUP BY
    P.id,
    P.name,
    P.body,
    P.upvotes,
    P.downvotes
1 голос
/ 18 июня 2010

Я предполагаю, что вы пытаетесь сделать так, чтобы пользователь голосовал только один раз за каждое сообщение здесь.

Я бы не стал - я не буду - использовать отдельные таблицы для голосов «за» и «против». Добавьте тип голосования в свою таблицу голосов, и вам не понадобятся коррелированные подзапросы.

1 голос
/ 18 июня 2010

Вот мое мнение:

  1. Кажется, что таблицы "UpVotes" и "DownVotes" имеют одинаковую структуру и могут быть объединены в одну таблицу.

  2. Отношение между таблицей "Post" и "Up / DownVotes" может быть ограничено внешним ключом.

  3. Хотя я не уверен в разнице в производительности, но я думаю, что было бы лучшеиспользовать механизм «соединения» вместо того, чтобы вкладывать два оператора выбора в оператор выбора.
0 голосов
/ 18 июня 2010

Вы можете использовать объединения для достижения того же результата, и я ожидаю, что объединения будут работать намного эффективнее, чем встраивание.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...