我有一个存储过程,它使用逗号分隔的ID字符串。我将它们拆分并放入临时表中并使用从其他表中提取记录,其中id为IN [table]
当为param传入一个id时,是否可以使用相同的过程?我可以编写第二个存储过程,它可以完全相同,但是其中id = @id 。
我有很多存储过程,其中可以传入多个ID或只传递一个。我是否尝试重用现有过程或编写新过程?性能是否显着?
答案 0 :(得分:2)
你可能想尝试JOIN而不是WHERE id IN - 尽管我认为你会得到相同的查询计划。
所以我假设你在做:
SELECT COl1, Col2, ...
FROM MyTable
WHERE id IN (SELECT id FROM @MyTempTable)
在这种情况下,等效的JOIN语法为:
SELECT COl1, Col2, ...
FROM MyTable AS T1
JOIN @MyTempTable AS T2
ON T2.id = T1.id
并且在第二种情况下是否有1行或多行,如果[id]被索引(假设它是你桌面上的PK,并使用聚集索引),它将非常有效。
(请注意,如果你在@MyTempTable中有DUP ID,你也会收到来自MyTable的欺骗:()
为了获得最佳性能,值得明确地将[id]声明为临时表上的PK(但考虑到它只保留几行,它可能不会产生太大的赔率)
DECLARE @TempTable TABLE
(
id int NOT NULL,
PRIMARY KEY
(
id
)
)
答案 1 :(得分:2)
在我观察到性能问题之前,我不会担心只有一个项目的性能损失。查询优化器很聪明,可能很好地处理这个项目,但即使它没有,你的例程可能在其他地方最慢。
我会看一下字符串解析,临时表创建和插入临时表的性能。尽可能快地进行这些操作会对整体性能产生更大的影响,而不是使用或者=对于单项情况。
答案 2 :(得分:1)
您可以使用相同的过程,但使用条件语句来确定use是否使用IN子句。
IN受到性能影响;执行计划应该为你详细说明。
答案 3 :(得分:1)
正如rde6173所说,在临时表上执行COUNT以确定要使用哪个SELECT查询。
答案 4 :(得分:1)
既然你已经指定它是逗号分隔的列表,你可以在你的sproc中做这样的事情:
IF (CHARINDEX(',', @id) = 0)
BEGIN
-- the @id parameter contains a single value
SELECT *
FROM your_table
WHERE id = @id -- maybe need to cast @id if the column isn't a string
END
ELSE
BEGIN
-- the @id parameter contains a comma-delimited list
-- only perform the expensive splitting logic at this point
-- eg, SET @yourTempTable = dbo.SplitCommaDelimitedIDsIntoTable(@id)
SELECT *
FROM your_table
WHERE id IN (SELECT id FROM @yourTempTable)
END
答案 5 :(得分:1)
创建临时表(不是表变量)时,它具有统计信息。因此,优化器将确定最佳计划,并且一个ID的最佳计划可能与10个ID相同,但对于50K ID,它可以选择不同的计划。 因此,除非您有性能问题,否则我不会尝试进一步优化它。