SQL IN对性能有害吗?

Vic*_*ues 60 sql sql-server-2000

我有一个查询做类似的事情:

SELECT FieldX, FieldY FROM A
WHERE FieldW IN (108, 109, 113, 138, 146, 160,
307, 314, 370, 371, 441, 454 ,457, 458, 479, 480,
485, 488, 490, 492, 519, 523, 525, 534, 539, 543,
546, 547, 550, 564, 573, 629, 642, 643, 649, 650,
651, 694, 698, 699, 761, 762, 768, 772, 773, 774,
775, 778, 784, 843, 844, 848, 851, 852, 853, 854,
855, 856, 857, 858, 859, 860, 861, 862, 863, 864,
865, 868, 869, 871, 872, 873, 891) 
Run Code Online (Sandbox Code Playgroud)

IN子句有这么多选项,对查询性能有害吗?我在我的应用程序中遇到很多超时,我相信它可能是这类问题的根源.我可以使用任何好的SQL提示优化查询而不删除数字吗?

编辑:

@KM这些是不同表中的键.这是一个论坛应用程序,简要解释:c#从数据库中获取所有论坛并将其存储在应用程序缓存中.在C#调用获取这些论坛和该用户的线程的过程之前,c#会对"所有论坛"集合进行一些逻辑过滤,考虑权限和一些业务逻辑.超时发生在数据库上而不是应用程序本身.在查询上执行所有这些逻辑将需要大量内部联接,并且我不能100%确定我可以在过程中完成所有这些操作.

我正在使用SQL Server 2000

LBu*_*kin 121

使用可能对性能产生影响的IN运算符编写查询时需要考虑几个因素.

首先,IN子句通常由大多数数据库在内部重写,以使用OR逻辑连接.因此col IN ('a','b','c')改写为:(COL = 'a') OR (COL = 'b') or (COL = 'c').假设您有索引,两个查询的执行计划可能相同col.

其次,当使用IN或OR与可变数量的参数时,您导致数据库必须重新解析查询并在每次参数更改时重建执行计划.为查询构建执行计划可能是一个昂贵的步骤.大多数数据库使用EXACT查询文本作为键来缓存它们运行的​​查询的执行计划.如果执行类似的查询但在谓词中使用不同的参数值 - 您很可能会导致数据库花费大量时间来解析和构建执行计划.这就是强烈建议使用绑定变量作为确保最佳查询性能的方法的原因.

第三,许多数据库对它们可以执行的查询的复杂性有限制 - 其中一个限制是可以包含在谓词中的逻辑连接词的数量.在您的情况下,几十个值不可能达到数据库的内置限制,但如果您希望将数百或数千个值传递给IN子句 - 它肯定会发生.在这种情况下,数据库将简单地取消查询请求.

第四,在并行环境中不能总是最佳地重写谓词中包含IN和OR的查询.在各种情况下并行服务器优化都没有得到应用 - MSDN对优化并行查询提供了不错的介绍.通常情况下,使用UNION ALL运算符的查询在大多数数据库中都是可以并行化的 - 并且在可能的情况下优先于逻辑连接符(如OR和IN).

  • 如果我们使用内连接而不是 IN 运算符会怎样?它会提高性能吗? (2认同)

tek*_*ues 5

如果你在FieldW上有一个很好的索引,那么使用IN是完全正确的.

我刚刚测试过,SQL 2000在使用IN时进行了聚簇索引扫描.

  • 那不一定是件好事.它应该是进行查找而不是扫描,这表明使用IN并非"完全正确".但是桌子的大小,基数和其他因素也很重要. (2认同)
  • 实际的问题是应用程序超时,可能是在这个查询上,可能是因为速度慢,可能是因为锁定。这距离构建哈希表的能力还有很长的路要走。难道您不想至少先看看查询计划吗?只有当我们知道它是一个问题时,该查询才值得改进。 (2认同)

Qua*_*noi 5

您可以尝试创建临时表,将值插入其中,并在IN谓词中使用该表.

AFAIK,SQL Server 2000无法构建常量集的哈希表,这剥夺了优化器使用a的可能性HASH SEMI JOIN.

只有当你没有索引时FieldW(这应该有),这才有用.

您还可以尝试将您的列FieldXFieldY列包含在索引中:

CREATE INDEX ix_a_wxy ON a (FieldW, FieldX, FieldY)
Run Code Online (Sandbox Code Playgroud)

这样只能使用索引来提供查询.

SQL Server 2000缺少INCLUDE选项CREATE INDEX,这可能会降低DML性能,但会提高查询性能.

更新:

从你的执行计划我看,你需要一个复合索引 (SettingsID, SectionID)

SQL Server 2000确实可以从常量列表中构建一个哈希表(并且这样做),但Hash Semi Join最有可能的效率低于Nested Loop查询查询.

只是旁注:如果您需要知道满足WHERE条件的行数,请不要使用COUNT(column),请COUNT(*)改用.

A COUNT(column)不计算column值所在的行NULL.

这意味着,第一,你可以得到你没有想到的结果;第二,优化器将需要做一个额外的Key Lookup/ Bookmark Lookup如果你的列不属于服务于指数WHERE的条件.

既然ThreadId似乎是一个CLUSTERED PRIMARY KEY,它可以用于这个查询,但总体上要尽量避免它.


Ste*_*erg 5

根据您的数据分布,WHERE 子句中的附加谓词可能会提高性能。例如,如果 id 集相对于表中的总数较小,并且您知道 id 相对较近(也许它们通常是最近添加的,因此聚集在范围的高端),您可以尝试包含谓词“AND FieldW BETWEEN 109 AND 891”(在 C# 代码中确定集合中的最小和最大 id 之后)。对这些列(如果有索引)进行范围扫描的速度可能比当前使用的要快。