WHERE ID IN(1,2,3,4,5,...)最有效吗?

Jan*_*ich 15 sql t-sql sql-server

我知道这个话题已被打败,但似乎互联网上的许多文章经常寻找最优雅的方式,而不是最有效的方法来解决它.这是问题所在.我们正在构建一个应用程序,其中一个公共数据库查询将涉及基于用户提供的ID列表的操作(SELECT和UPDATE).有问题的表预计会有数十万行,并且用户提供的ID列表可能无限制,它们最有可能是数十或数百(我们可能会出于性能原因限制它).

如果我对数据库如何工作的理解是正确的,那么最有效的方法是简单地使用WHERE ID IN (1, 2, 3, 4, 5, ...)构造并动态构建查询.问题的核心是ID的输入列表将是任意的,因此无论数据库多么聪明或者我们如何巧妙地实现它,我们总是有一个随机的整数子集开始,所以最终每个方法都必须WHERE ID IN (1, 2, 3, 4, 5, ...)无论如何,内部归结为类似的东西.

人们可以在网络上找到很多方法.例如,一个涉及声明一个表变量,将ID列表作为逗号分隔的字符串传递给存储过程,在存储过程中将其拆分,将ID插入表变量并在其上加入主表,即类似这个:

-- 1. Temporary table for ID’s:
DECLARE @IDS TABLE (ID int);

-- 2. Split the given string of ID’s, and each ID to @IDS.
-- Omitted for brevity.

-- 3. Join the main table to @ID’s:
SELECT MyTable.ID, MyTable.SomeColumn
FROM MyTable INNER JOIN @IDS ON MyTable.ID = @IDS.ID;
Run Code Online (Sandbox Code Playgroud)

把字符串操作的问题放在一边,我认为在这种情况下本质上发生的是在第三步中SQL Server说:"谢谢,这很好,但我只需要一个ID的列表",它会扫描表变量@IDS,然后n寻找MyTable其中n是ID的数量.我做了一些基本的性能评估并检查了查询计划,看来这就是发生的事情.所以表变量,字符串连接和拆分以及所有额外的INSERT都是无用的.

我对么?或者我错过了什么?真的有一些聪明而有效的方法吗?基本上,我所说的是SQL Server必须执行n索引搜索而不管是什么并且制定查询,这WHERE ID IN (1, 2, 3, 4, 5, ...)是最直接的方式.

Joe*_*orn 11

嗯,这取决于真正发生的事情.用户如何选择这些ID?

而且,这不仅仅是效率; 还有担心的安全性和正确性.用户何时以及如何告诉数据库他们的ID选择?如何将它们合并到查询中?

将选定的ID放入可以加入的单独表中(或使用WHERE EXISTS)可能会好得多.

我会告诉你,你不可能做得比IN (1,2,3..n)一个小的(用户生成的)n 更好.但是你需要考虑如何生成该查询.你打算使用动态SQL吗?如果是这样,你将如何确保注射?服务器是否能够缓存执行计划?

此外,使用额外的表通常更容易.假设您正在为电子商务网站构建购物车.而不是担心跟踪购物车客户端或会话,每次用户做出选择时,最好更新ShoppingCart表.这也避免了如何安全地为查询设置参数值的整个问题,因为您一次只进行一次更改.

不要忘记古老的谚语(向本杰明富兰克林道歉):

交易正确性的人也不值得


Dea*_*n J 6

小心; 在许多数据库中,IN(...)仅限于IN子句中固定数量的事物.例如,我认为在Oracle中它是1000.这很重要,但可能值得了解.


Rod*_*igo 5

IN条款不保证a INDEX SEEK.我在一个内存很少的Pocket中使用SQL Mobile版之前遇到了这个问题.用OR子句列表替换IN(列表)使我的查询提高了400%aprox.

另一种方法是使用临时表来存储ID并将其与目标表连接,但是如果经常使用此操作,则永久/索引表可以帮助优化器.