此SQL select代码是否遵循良好实践?

此SQL select代码是否遵循良好实践?,sql,mysql,sqlite,Sql,Mysql,Sqlite,我正在使用SQLite,稍后将移植到MySQL(5) 我想知道我是否在做不该做的事。我特意尝试了设计,所以我将与0而不是1进行比较(我将hasApproved更改为NotApproved,这没什么大不了的,而且我还没有编写任何代码)。有人告诉我不需要写子查询,但我在这里写。我的投票表只是id、ip、postid(我不认为我可以将该子查询编写为一个连接?),这几乎就是我所想的全部内容 我并不真正关心命名约定,因为表是通过反射创建的,到处都是 select id, name,

我正在使用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 ?, ?"

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

我猜您是在尝试确保用户在这里的每篇文章上只投票一次

我不会——我不会——用单独的表格来表示赞成票和反对票。将投票类型添加到投票表中,您将不需要相关子查询。

以下是我的意见:

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

  • 表“Post”和“向上/向下投票”之间的关系可以由外键约束

  • 虽然我不确定性能差异,但我认为使用“join”机制比将两个select语句嵌套在一个select语句中更好

  • 既然你在问关于良好实践的问题。。。Posts表中出现的“向上投票”和“向下投票”看起来像是在复制数据库中的数据。这是一个问题,因为现在你总是要担心数据是否同步和正确。如果您想知道向上投票的数量,然后计算它们,不要将它们也存储在Post表中。我不确定你在做什么,但这只是猜测

    关于你的问题。。。使用联接子查询而不是如何使用它,可能会获得更好的性能。使用标量子查询作为列,必须为返回的每一行运行一次。如果返回一堆行,那么这可能会对性能造成相当大的影响。相反,请尝试:

    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
    

    注意,我有两个连接,因为它是2个值,而不是or。投票表确实使用post作为FK,除非我有一个列可以检查(一个bool说up,否则我知道它down),否则我不知道如何将它写为联接。我需要它才能将其作为联接写入吗?将上/下投票保留在一个带有布尔字段的表中是个好主意。没有必要使用join,但当数据库变大时,您可能需要它来提高性能。您的意思是什么?在这两种情况下,我仍然需要将我的投票列表加入帖子。哦,对不起,我只是指SQL join语句(select…join…),如何?我没有专栏可供选择,实际上我允许“向上”和“向下”投票。这真的是同意和不同意,你可以同时做这两件事。既然我两者都能做到,我应该把它们放在同一张桌子上吗?我认为在2个表中,然后在1个表中,检查IP地址并编写额外的和voteType(或=)myVoteType.Yikes更容易。考虑到不太可能需要第三种(第四种等)投票字段,我仍然会选择一个投票表,两个投票字段,一个代表上升,一个代表下降。每个用户每个帖子一个投票表记录。使用用户id上的帖子加入投票,选择两个投票字段,并在应用程序中采取适当的操作。另外,我相信你对使用IP地址进行身份识别时可能出现的问题非常了解……左外连接的作用与我的不同。我通过查看我的IP(这是一个类似fmylife的网站,类似wiki,不需要登录),检查我是否对帖子投了上/下票。外部联接中的()部分不是意味着它在执行子查询吗?另外,当您说“为返回的每一行运行一次”时,这与应用于每一行的联接不一样吗?哦,上/下计数由插入、更新和删除时的触发器维护。在任何情况下都不应该出现错误,但这并不重要,我想我可以在以后运行检查。不,连接肯定不一样-SQL处理集合,而连接是集合操作,因此速度要快得多。虽然有一个子查询,但在本例中该查询只运行一次,结果将一直保留到SQL完成为止——这是因为它们是不同类型的子查询(相关与非相关)。至于触发器和数据永远不会失去同步,我只想说,“著名的遗言”;)第一个是相关子查询,它为结果集中的每一行触发一次。第二个是派生表,它对整个数据集只触发一次。它几乎总是明显更快。基本上,99%的时间都不希望在数据库中进行逐行处理。数据库针对基于集合的操作进行了优化。有问题吗。你的
    @0
    是什么?我以前从未见过这种特殊语法,因为您的数据库引擎似乎使用位置参数(问号)。@Lasse:我相信这是一个编号参数。它将替换为查询中第一个(基于0的索引)未命名参数的给定值。不过,这只是从用法推断出来的猜测。qstarin知道了@0将是第一个“?”,这是它上面类似行中的ip地址。所有的?每个?上的替换为@where index+?。