SQL Server "<>" 运算符与具有几百万行的表上的 "=" 相比非常慢

Posted

技术标签:

【中文标题】SQL Server "<>" 运算符与具有几百万行的表上的 "=" 相比非常慢【英文标题】:SQL Server "<>" operator is very slow compared to "=" on table with a few million rows 【发布时间】:2011-09-14 15:51:26 【问题描述】:

我有两张桌子。表单有 ~77000 行。日志有大约 270 万行。

以下查询在不到一秒的时间内返回“30198”:

SELECT COUNT(DISTINCT logs.DOCID) FROM logs, forms WHERE logs.DOCID = forms.DOCID;

到目前为止,这个查询已经运行了大约 15 分钟,但仍未完成:

SELECT COUNT(DISTINCT logs.DOCID) FROM logs, forms WHERE logs.DOCID <> forms.DOCID;

为什么“不等于”查询如此慢得多?

【问题讨论】:

WHERE NOT logs.DOCID = forms.DOCID 呢? 您是否要查找在forms 中不存在对应值的logs.DOCID 值?如果是这样,请尝试SELECT COUNT(*) FROM (SELECT DOCID FROM logs EXCEPT SELECT DOCID FROM forms ) T @Martin - 您的查询在 8 秒内返回。谢谢! 【参考方案1】:

因为= 将连接操作减少到每个表中的一个匹配行(假设这些 docid 是唯一的)。

这样想——你和 5 个男孩和 5 个女孩共舞:

Adam      Alice
Bob       Betty
Charly    Cathy
Dick      Deb
Evan      Elly

您通过第一个字母将它们配对。所以

Adam->Alice
Bob->Betty
etc...

单对

但是,如果您通过“首字母不匹配”将它们配对,您最终会得到:

Adam->Betty
Adam->Cathy
Adam->Deb
Adam->Elly
Bob->Alice
etc...

你已经大大增加了配对的数量。这就是您的&lt;&gt; 查询需要这么长时间的原因。您实际上是在尝试获取m x n 行,而不仅仅是min(m,n)。有了这些数据,您最终会得到 25 行,而不是 5 行。对于您指定的表大小,您正在使用 77,000 * 2,700,000 = 2079 亿行,减去两个 id 匹配的 77,000 行,总共 207,899,923,000 行连接的数据集。


根据您的查询要求,尝试左连接并查找空的右侧记录:

SELECT DISTINCT logs.DOCID
FROM logs
LEFT JOIN forms ON logs.DOCID = forms.DOCID
WHERE forms.DOCID IS NULL

【讨论】:

+1 我猜 OP 可能需要 NOT INNOT EXISTSEXCEPT SELECT COUNT(*) FROM (SELECT DOCID FROM logs EXCEPT SELECT DOCID FROM forms ) T 谢谢大家。这有助于我更好地理解 SQL。 SELECT COUNT(DISTINCT logs.DOCID) FROM logs, formId WHERE logs.DOCID NOT IN (SELECT forms.DOCID FROM forms); 在 11 秒后返回。 @Martin Smith - SELECT COUNT(*) FROM (SELECT DOCID FROM logs EXCEPT SELECT DOCID FROM forms) T; 在 8 秒内返回。 @TRedman 一个建议,即使您可能会接受 Martin 的 EXCEPT 建议 - 不要使用 NOT IN,除非您绝对 100% 确定内部的列不能是 NULL . NOT EXISTS 通常优于 NOT IN @TRedman - 我强烈建议您停止使用, 表示法。您上面评论中的代码正在执行此操作... 获取logs 表,排除DOCID 不在forms 表中的每条记录,然后将所有剩余记录加入到整个表中forms 表。 (每条记录 77000 个匹配项,一个叉积,我敢肯定你不是这个意思)【参考方案2】:

两个原因:

等价查询一般可以使用索引(如果有的话),而不等价查询则不能

&lt;&gt; 返回更多数据。

您对&lt;&gt; 的查询是虚假的。它应该返回什么?

【讨论】:

感谢您的回复。它应该返回〜3800。我正在日志表中查找与表单表中的 formID 不对应的任何 formID。上面已经有人回答了-我应该使用EXISTSIN 是的。另一种可能性是RIGHT OUTER JOINIS NULL【参考方案3】:

这完全取决于表中值的分布。例如,如果您正在搜索的列在 99.99% 的行中具有相同的值 (= forms.DOCID),并且只有一行具有不同的值,您会看到完全相反的行为。

【讨论】:

以上是关于SQL Server "<>" 运算符与具有几百万行的表上的 "=" 相比非常慢的主要内容,如果未能解决你的问题,请参考以下文章

spring 事务 sqlserver 锁表问题

log4net在sql server中成功,但不能写入access?

SQL Server "<>" 运算符与具有几百万行的表上的 "=" 相比非常慢

sql server 2008怎么安装实例

从 VB Access 调用 UDF(Sql server)“表达式中的未定义函数 <函数名>”

server.urlencode加密问题