这个SQL选择代码是否遵循良好实践?

时间:2010-06-18 15:25:11

标签: sql mysql sqlite

我正在使用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 个答案:

答案 0 :(得分:1)

我猜你正在努力确保用户只在每个帖子上投票一次。

我不会 - 我不 - 使用单独的表格进行投票和投票。将投票类型添加到您的投票表中,您将不需要相关的子查询。

答案 1 :(得分:1)

以下是我的意见:

  1. 似乎表“UpVotes”和“DownVotes”具有相同的结构,可以合并到一个表中。

  2. 表“Post”和“Up / DownVotes”之间的关系可以用外键约束。

  3. 虽然我不确定性能差异,但我认为最好使用“join”机制而不是在select语句中嵌套两个select语句。

答案 2 :(得分:1)

由于您正在询问良好做法......您的帖子表格中出现的“upvotes”和“downvotes”看起来像是在复制数据库中的数据。这是一个问题,因为现在你总是要担心数据是否同步和正确。如果你想知道upvotes的数量然后计算它们,也不要将它们存储在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

答案 3 :(得分:0)

您可以使用连接来实现相同的功能,我希望连接比嵌入选择更有效。