SQL Server记录计数差异

时间:2018-11-30 17:25:46

标签: sql sql-server sql-server-2012

我正在编写一个程序,允许用户选择给定表的子集(在SQL Server 2012中,但希望我缺少的内容和版本无关紧要)。该程序检查是否有任何子集重叠,以及它们(一起)是否对整个表进行分区。

我遇到了我真的不明白的情况。我不能使用真实名称或值,但这是设置:

  • 我正在查看给定的表(称为TABLE_X),并且
  • 一些特殊的谓词(例如A,B,C和D),我希望它们相互排斥,但不会覆盖整个表...
  • 我希望查询任何谓词对(例如WHERE(A)AND(B))的交集都不会返回任何记录,并且确实是这种情况
  • 如果表中有5,000,500条记录,而谓词联合有2,000,000条记录,那么我希望联合的补充部分将有3,000,500条记录;最后一点是我遇到了问题

在记录计数主题中,这是我所发现的:

  • 如果我从TABLE_X中选择count(1),则会得到(例如)5,000,500条记录
  • 如果我从TABLE_X中选择count(1),其中(A)或(B)或(C)或(D),我将获得2,000,000条记录
  • 如果我从TABLE_X中选择count(1)而不是((A)或(B)或(C)或(D)),我将获得3,000,000条记录
  • 如果我从TABLE_X中选择count(1),而不是((A)或(B)或(C)或(D))或((A)或(B)或(C)或(D)),我得到5,000,000条记录

因此,我看到谓词及其补语的并集导致基数比表本身的基数低。这似乎违反了逻辑。

自然,我问自己NULL值是否有某种影响。请注意,谓词A,B,C和D是相当简单的布尔表达式,都涉及相同的列,例如:c1,c2和c3。我发现的内容对我来说并没有说明问题:

  • 如果我从TABLE_X中选择count(1),其中不是((A)或(B)或(C)或(D))和((c1为null)或(c2为null)或(c3为null) ),我得到550条记录
  • 如果我从TABLE_X中选择count(1),其中((A)或(B)或(C)或(D))和((c1为空)或(c2为空)或(c3为空)) ,我得到0条记录

所以我希望两个涉及空检查的查询以某种方式产生记录计数差异(即500),但是我却得到一个新的数字(即550)。

我可能会处理空支票,从而击败自己,但老实说我不知道​​。

我还检查了该表是否具有主键,甚至对主表进行了计数分组以确认没有重复的记录。没有重复的记录。

另一个奇怪的地方(这不是我的表)是该表具有一个PK和一个聚集索引,但是PK不是聚集索引(它们是不同的-相同的列,不同的列顺序... )

因此,我的问题是:如何确定为什么我看到记录计数似乎违反了逻辑(如上所述)?

请注意:我知道这个站点期望“研究努力”,但是我什至不知道要搜索什么-对我来说这是基本的布尔逻辑。我试图帮助自己的尝试是检查零值方面,这使我震惊。

1 个答案:

答案 0 :(得分:1)

将我的评论重写为每个OP请求的答案。

发生这种情况的原因有很多:

  • 您的谓词中可能存在逻辑错误
  • 可能存在一些会话级设置,这些设置会巧妙地改变谓词的评估方式(ansi nulls on / off或类似值)
  • SQL Server中可能存在一个错误(这种情况很少发生,但如果存在,则SQL团队将希望帮助对其进行调查和修复)

您在帖子中指出,您曾尝试进行基于CTE的调用,以查看试图缩小bug范围的各种模式。根据SQL Server解析和编译这些查询的方式,您应该尝试其他方法。 CTE被视为视图,并在编译期间内联。因此,如果SQL中存在逻辑错误(第三种情况),那么添加CTE只会在您的实验中重复同样的问题,并不一定能帮助您缩小范围。

我建议您将每个测试的结果都放入临时表中。然后,我建议您针对原始查询和其他模式使用EXCEPT ALL / INTERSECT ALL查询运行那些临时表,以缩小您无法解释的500行。如果可以找到这些特定的行,则可以进行较小的复制,以隔离问题。 (如果您要与Microsoft客户支持联系,则可以通过在致电之前对问题进行最小化的复制来帮助加快该过程。)

我希望这有助于深入您的谜底。祝你好运。

Conor

建筑师,SQL Server