使用SQL识别表中不存在的值的最有效方法

时间:2012-06-26 17:59:58

标签: sql performance sql-server-2008

我目前需要搜索项目表以验证用户输入的项目列表 项目表包含每个项目的唯一主键,称为ItemId(对应于用户输入的值)。
给定一个10000(一万)行的表,搜索ItemId列并确定用户输入的任何项目在表中是否存在的最有效方法是什么?

例如,给出表格:

ItemId       Color      Price
 1000         Blue       3.00  
 1001          Red       4.00  
 1003        Green       1.25  

用户输入以下内容:
    1000     1001     1002

我想抛出一个错误来警告用户其中一个项目(1002)无效。我不需要专门识别无效的项目,只需要表中不存在一个或多个项目。我尝试过使用IF NOT EXISTS以及EXCEPT,但我没有在效率方面感受到“最佳实践”。通常情况下,我会检查执行计划,但我真的不知道从哪里开始。我非常感谢任何建议!

2 个答案:

答案 0 :(得分:0)

就个人而言,我会在我的存储过程中使用Table-Valued参数,然后只需LEFT JOIN到表中并查找NULL。

CREATE TYPE ItemTableType AS TABLE 
( ItemId INT);
GO

CREATE PROCEDURE dbo.usp_GetItems
    @Items ItemTableType READONLY
AS 

SET XACT_ABORT ON;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET NOCOUNT ON;

IF EXISTS (SELECT * 
           FROM dbo.MyItemTable i1 
           LEFT JOIN @Items i2 ON i1.ItemId = @i2.ItemId 
           WHERE i2.ItemId IS NULL)

    RAISERROR('Item does not exist', 16, 1)
ELSE
    SELECT i1.*
    FROM dbo.MyItemTable i1
    JOIN @Items i2 on i1.ItemId = @i2.ItemId

GO

我能想到的另一种可能性是对最终结果进行计数。

执行计数:

DECLARE @CommaCount INT

SET @CommaCount = (select len(@ItemIds)-len(replace(@ItemIds,',','')))

然后当您执行SELECT时,只需将结果与计数进行比较:

SELECT * 
FROM dbo.MyItemTable
WHERE ItemId IN (@ItemIds)

IF(@@ROWCOUNT != @CommaCount)
    RAISERROR('Item does not exist', 16, 1)

答案 1 :(得分:0)

我同意Chris的回答,因为使用TVP是传递用户提供的值的好方法,但会做出以下更改。

使用主键声明TVP

CREATE TYPE ItemTableType AS TABLE 
( ItemId INT PRIMARY KEY);

使用NOT EXISTS代替OUTER JOIN ... NULL。这是作为有效的反半连接实现的。 OPTION (RECOMPILE)提示和PRIMARY KEY应该为优化器提供足够的信息,以便为两个表的大小选择最佳的连接策略。

SELECT CASE
         WHEN EXISTS (SELECT *
                      FROM   @Items i
                      WHERE  NOT EXISTS (SELECT *
                                         FROM   dbo.MyItemTable it
                                         WHERE  i1.ItemId = it.ItemId)) THEN 0
         ELSE 1
       END
OPTION (RECOMPILE) 

OUTER JOIN ... NULL可以结束所有行的外部联接,然后使用过滤器删除NOT NULL,但效率较低(this article底部的示例),另见{{ 3}}