1

現在、ユーザーが入力したアイテムのリストを検証するために、アイテムのテーブルを検索する必要があります。
項目のテーブルには、ItemId (ユーザーが入力した値に対応) と呼ばれる各項目の一意の主キーが含まれています。
10000 (1 万) 行のテーブルがある場合、ItemId 列を検索し、ユーザーが入力した項目のいずれかがテーブルに存在しないかどうかを判断する最も効率的な方法は何でしょうか?

たとえば、次の表があるとします。

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

そして、ユーザーは次のように入力します:
1000 1001 1002

エラーをスローして、アイテムの 1 つ (1002) が無効であることをユーザーに警告したいと思います。無効なアイテムを具体的に特定する必要はありません。テーブルに 1 つ以上のアイテムが存在しないことだけを確認してください。IF NOT EXISTS と EXCEPT を使用してみましたが、効率の点で「ベスト プラクティス」の感触が得られません。通常、私は実行計画を検討しますが、どこから始めればよいのかよくわかりません。あらゆる提案をいただければ幸いです。

4

2 に答える 2

0

TVPを使用することは、ユーザーが指定した値を渡す良い方法ですが、次の変更を行うという点で、Chrisの回答に同意します。

主キーで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 ... NULLNOT NULL最終的にすべての行を外部結合し、その後、効率の低いフィルターを使用して行を削除する可能性があります(この記事の下部にある例)。「左外部結合と存在しない」も参照してください。

于 2012-06-26T18:48:16.200 に答える
0

個人的には、ストアド プロシージャでテーブル値パラメーターを使用し、単純にテーブルに 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)
于 2012-06-26T18:15:26.313 に答える