我工作的地方最近我被告知在查询中使用distinct是一个程序员的坏迹象。所以我想知道我猜不使用此功能的唯一方法是使用分组。
我的理解是,除了阅读之外,distinct函数的工作方式与组相似。一个独特的函数检查每个单独的选择标准与一个组,通过该组,相同的事情只作为一个整体进行。
请注意,我只会报告。我不创建/更改数据。所以我的问题是我应该使用distinct或group by的最佳实践。如果两者都没有替代品。也许group by应该用在比我非实际例子更复杂的查询中,但是你明白了。我找不到真正解释为什么或为什么不在我的查询中使用不同的答案
select distinct
spriden_user_id as "ID",
spriden_last_name as "last",
spriden_first_name as "first",
spriden_mi_name as "MI",
spraddr_street_line1 as "Street",
spraddr_street_line2 as "Street2",
spraddr_city as "city",
spraddr_stat_code as "State",
spraddr_zip as "zip"
from spriden, spraddr
where spriden_user_id = spraddr_id
and spraddr_mail_type = 'MA'
VS
select
spriden_user_id as "ID",
spriden_last_name as "last",
spriden_first_name as "first",
spriden_mi_name as "MI",
spraddr_street_line1 as "Street",
spraddr_street_line2 as "Street2",
spraddr_city as "city",
spraddr_stat_code as "State",
spraddr_zip as "zip"
from spriden, spraddr
where spriden_user_id = spraddr_id
and spraddr_mail_type = 'MA'
group by "ID","last","first","MI","Street","Street2","city","State","zip"
答案 0 :(得分:18)
数据库很聪明地识别您的意思。我希望你的两个查询同样表现良好。维护查询的其他人必须知道您的意思。如果您真的想要检索不同的记录,请使用DISTINCT
。如果您打算进行汇总,请使用GROUP BY
看看this question。有一些很好的答案可能有所帮助。
答案 1 :(得分:8)
@zedfoxus提供的答案对于理解上下文非常有用。
但是,如果数据设计正确,我不相信您的查询应该需要不同的记录。
您似乎正在选择表spriden
的主键,因此所有数据应该是唯一的。您还要加入spraddr
表格;该表确实包含有效的重复数据吗?或者是否有一个额外的连接标准需要过滤掉那些重复项?
这就是为什么我对使用" distinct
" - spraddr
表格可能包含您应该用来过滤数据的其他列,以及" distinct
"可能正在隐藏那个。
此外,您可能正在生成一个庞大的结果集,需要通过" distinct"子句,可能会导致性能问题。例如,如果spraddr
中每行spriden
有100万行,则应使用" is_current"标志找到2或3"真实"的。
最后,当我看到" group by"用来代替不同的,不是因为它错了",而是因为在风格上,我认为group by应该用于聚合函数。这只是个人偏好。
答案 2 :(得分:5)
在您的示例中distinct
和group by
执行相同的操作。我认为您的同事意味着您的查询不应该在第一个实例中返回重复项,并且您应该能够在没有distinct
或group by
子句的情况下编写查询。您可以通过扩展join
条件来减少重复项。
答案 3 :(得分:4)
问他们为什么这是一个不好的做法。许多人通过阅读本书的第一页或谷歌搜索的第一个结果来制定规则或提出他们认为不好的做法。如果它能够完成任务并且不会导致任何问题,那么就没有理由通过寻找替代方案来创造更多的工作。从您发布的两个选项中我也会使用不同的选项,因为它更短,更易于阅读和维护。
答案 4 :(得分:0)
如果您的查询正确,DISTINCT和GROUP BY提供相同的结果集,但您的同事说明DISTINCT隐藏了问题是正确的。如果您错过了加入并使用GROUP BY,那么您将获得比您期望的更多信息。如果您缺少连接并使用DISTINCT,则SQL引擎将执行无限制(或部分限制)连接,缩小结果范围,然后提出预期答案。
除了产生超出必要数据的明显性能下降之外,还存在填充tempdb的风险(即:tempdb所在的硬盘驱动器上的空间不足)。
在生产中使用GROUP BY。
答案 5 :(得分:0)
任何人告诉您使用DISTINCT
本身就是一个不好的信号是错误的。实际上,这完全取决于您要首先使用DISTINCT
解决的问题。
如果您查询的表预期具有某些字段或字段组合的重复值,并且您要报告值列表或值组合(而不执行它们上的任何聚合),那么DISTINCT
是最明智的选择。在我看来,仅因为有人认为不应该使用GROUP BY
而使用DISTINCT
并没有什么意义。
如果OTOH,您发现查询中存在一个错误,意味着将返回重复的值,则不应使用DISTINCT
或GROUP BY
来消除此错误。相反,您应该找出错误的原因并加以解决。
使用DISTINCT
作为安全网也是一种不好的做法,因为它可能隐藏问题,而且计算量也很大(通常O( n log n < / em>)或O( n 2 ))。在这种情况下,我看不到使用GROUP BY
会对您有所帮助。
答案 6 :(得分:0)
是的,当我在某人的查询中碰到它时,Distinct往往会在我的脑海中发出一点警报。在某些情况下,它是必需的,但是大多数数据模型都不需要。它往往是不得不使用它的不得已的方法或异常情况。这也可能是由于错误的应用程序位于数据库之上,导致重复的条目被插入或更新为重复的(同样,没有相应的数据库级别约束来阻止此类操作)。因此,首先要检查的是数据。这可能是不良的数据模型设计的迹象。但是最有可能的是,查询应该不会进入重复行一直徘徊的选择阶段。
在构造大型查询时,通常我将从指定唯一字段的子查询的块开始,此后的任何子查询都必须对其进行内部联接或向左联接,但绝不增加或减少已定义的行数通过块查询..并记住要处理左联接的可能的NULL。
因此,例如,掘金查询还可以通过使用分区来选择正确的行,例如,选择联接表的最新行,或者在该阶段进行一些其他分组。
在您的示例中,我不希望重复。如果一个人可以有历史地址,那很好,但是您是否需要查看所有地址,或者仅查看最近的地址,并且如果有重复的地址,对于同一个人,这是否意味着错误地复制了数据,还是意味着人员离开了该地址,但稍后又返回了该地址...在这种情况下,select分区将解决该问题,其控制要比独特对象好得多。.特别是当其他人稍后将字段添加到查询中并破坏了独特性时。< / p>
这意味着所有其他数据都将悬挂在子查询的这个块中。您将其他可能的字段粘贴到核心字段集的右侧。
如果Distincts是最后的选择,则通常将它们保留用于已知数据在该表中具有该字段集的重复条目的情况,这是完全正常的。在我看来,计划中的一个缓慢的事后选择过程尤其如此,特别是当返回的结果集很大时。我应该核实这些日子之一。