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...
你已经大大增加了配对的数量。这就是您的<>
查询需要这么长时间的原因。您实际上是在尝试获取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 IN
或 NOT EXISTS
或 EXCEPT
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】:
两个原因:
等价查询一般可以使用索引(如果有的话),而不等价查询则不能
<>
返回更多数据。
您对<>
的查询是虚假的。它应该返回什么?
【讨论】:
感谢您的回复。它应该返回〜3800。我正在日志表中查找与表单表中的 formID 不对应的任何 formID。上面已经有人回答了-我应该使用EXISTS
或IN
。
是的。另一种可能性是RIGHT OUTER JOIN
和IS NULL
。【参考方案3】:
这完全取决于表中值的分布。例如,如果您正在搜索的列在 99.99% 的行中具有相同的值 (= forms.DOCID)
,并且只有一行具有不同的值,您会看到完全相反的行为。
【讨论】:
以上是关于SQL Server "<>" 运算符与具有几百万行的表上的 "=" 相比非常慢的主要内容,如果未能解决你的问题,请参考以下文章
log4net在sql server中成功,但不能写入access?
SQL Server "<>" 运算符与具有几百万行的表上的 "=" 相比非常慢