如果使用IN子句,应使用逗号分隔值或表变量。

3
假设我们想将一个值数组作为参数传递给一个存储过程,在其中用作IN子句中的值。
在性能方面,以下哪种方式更好:
1. 将值作为逗号分隔的字符串进行传递。
Select * FROM myTable WHERE Id IN (@myConcatenatedValues)

或者

2- 将值作为一个表变量传递,该变量包含将这些值作为行的列

例如:

Select * FROM myTable WHERE Id IN (Select Id from @myVariableTable)

Thanks in advance


https://dev59.com/UnM_5IYBdhLWcg3w2XHw - Squirrel5853
@Secret Squirrel:你说得没错,但我的问题是关于IN子句的,而不是JOIN或EXISTS或其他什么东西。 - Mostafa Armandi
如果您传递逗号分隔的字符串,则必须在存储过程中使用预处理语句。但是,如果这些值已经存在于表中,最好传递表变量。 - Krishna Rani Sahoo
1个回答

5

我使用以下三个查询进行了快速测试:

DECLARE @UsersInString VARCHAR(255) = '1, 2, 3, 4, 5, 6, 7, 8, 9, 10'

/* Prone to SQL Injection, do not use like this! Sanitise your inputs */
EXEC (' SELECT * FROM [dbo].[User] WHERE UserID IN ( ' + @UsersInString + ' ) ')
GO

并且:

DECLARE @UsersInTable TABLE (
    UserID INT
)

INSERT INTO @UsersInTable
VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10)

SELECT *
FROM [dbo].[User] U
JOIN @UsersInTable UT ON UT.UserID = U.UserID

并且:

DECLARE @UsersInTable TABLE (
    UserID INT
)

INSERT INTO @UsersInTable
VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10)

SELECT *
FROM [dbo].[User] U
WHERE U.UserID IN (
    SELECT UserID
    FROM @UsersInTable
)

实际执行计划表明,在我的情况下,顶部查询更快;该查询仅使用了聚集索引查找(Clustered Index Seek)。
中间查询略慢,因为除了使用聚集索引查找之外,还在表变量上使用了表扫描(Table Scan)。
底部查询更慢,因为除了使用聚集索引查找和表扫描之外,还对表变量执行排序操作(Sort);人们会认为这是为了优化针对已排序聚集索引的IN ()查询。
然而,这在很大程度上取决于正在查询的列的索引方式以及构建字符串或表变量所需的时间。
一个相当重要的副笔记:将值作为逗号分隔的字符串传递可能会有风险。您必须使用字符串串联动态构造IN()语句,这可能会使您面临SQL注入的风险。

第二种情况使用IN(而不是使用JOIN)怎么样? - Mostafa Armandi
我在我的答案中添加了第三个查询。 - Luke Merrett
在定义表变量时,如果包含索引,是否会有其他差异?declare @severities table (SeverityId uniqueidentifier unique clustered) - Mr.Mindor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接