web-dev-qa-db-ja.com

ストアドプロシージャを同時に複数回実行すると、一時テーブルのフィルター処理されたインデックスの作成がブロックされる

SQL Server 2014で、最初のテーブル作成後に一時テーブルに1つ以上のフィルター処理されたインデックスを作成することに固有の既知のブロッキングの問題はありますか? (つまり、インラインインデックスの作成ではありません)

実際のコードを投稿することは許可されていません。それで、無実を保護するためにテーブル/列の名前を変更しました。以下の代表的な非常に大まかなロジックは、ストアドプロシージャの最初に含まれています。

ストアドプロシージャが同時に複数回実行されると、ブロッキングが発生すると思います。私のDMVクエリによると、ストアドプロシージャは最初の非クラスター化インデックス作成ステートメントでブロックされています。

CREATE TABLE #temp_table_name_goes_here (
    [the_first_col] BIGINT NULL
    ,[the_second_col] INT NULL
    ,[another_col] VARCHAR(20) NULL
    );

CREATE INDEX tmp_indx_temp_table_name_goes_here_1 ON #temp_table_name_goes_here (the_first_col)
WHERE the_first_col IS NOT NULL;

CREATE INDEX tmp_indx_temp_table_name_goes_here_2 ON #temp_table_name_goes_here (the_second_col)
WHERE the_second_col IS NOT NULL; 
4
Bryan Rebok

再現!

Paulが示唆したように、 SQL Query Stress を使用して、例を使用し、インラインでインデックスを作成するように変更して、問題を再現できました。

CREATE TABLE #temp_table_name_goes_here
     (
         the_first_col BIGINT NULL,
         the_second_col INT NULL,
         another_col VARCHAR(20) NULL,
         INDEX tmp_indx_temp_table_name_goes_here ( the_first_col ) 
               WHERE the_first_col IS NOT NULL,
         INDEX tmp_indx_outstanding_inventory ( the_second_col ) 
               WHERE the_second_col IS NOT NULL
     );

NUTS

もちろん、SQSは200の同時セッションを20回の反復で実行していたため、そこに到達するまでには多少の作業が必要でした。

私はSQL Server 2017を使用しているため、 Trace Flag 3427 を有効にしても状況は変わりませんでした。

Tempdbがシステムで最適に構成されていない場合は、そこから開始します。

  • コアごとに1つのデータファイル、最大8コア
  • トレースフラグ1117および1118を有効にする

それでも問題が解決しない場合は、マイクロソフトでサポートケースを開きます。このようなスケーラビリティの問題は、中心的なものでなければなりません。

ファローアップ

この質問 を見つけた後、テーブル変数を使用してテストを再試行することにしました。上記と同じ状況下で、同じ競合が観察されました。

DECLARE @temp_table_name_goes_here TABLE
     (
         the_first_col BIGINT NULL,
         the_second_col INT NULL,
         another_col VARCHAR(20) NULL,
         INDEX tmp_indx_temp_table_name_goes_here ( the_first_col ) 
               WHERE the_first_col IS NOT NULL,
         INDEX tmp_indx_outstanding_inventory ( the_second_col ) 
               WHERE the_second_col IS NOT NULL
     );

Jonathan Fite's コメントごとに、最初に明示的なDROP IF EXISTS(またはNOT NULL object_idの古いスタイルチェック)を使用して一時テーブルテストを再実行しました。

以前にこのエラーに遭遇したことがあります。私の解決策は、インデックスと一時テーブル(DROP IF EXISTS)を明示的に削除してから作成することでした。これは、同じセッションでストアドプロシージャが複数回実行された場合にのみ発生します。

これはdidのヘルプです。競合は存在しないか、最小限に抑えられました。

最後に明示的なDROP TABLEまたはDROP IF EXISTSを追加すると、奇妙な影響がありました。奇妙なことに、競合が一時テーブルの削除に切り替わりました。

NUTS

5
Erik Darling

つまり、インラインインデックスの作成ではありません

主な欠点は、DDLが作成後に実行されるため、一時テーブルが キャッシュの対象となる にならないことです。

これは、フィルター処理されたインデックスがなくても一時テーブルが適格であり、構造のキャッシュがワークロードにとって有益であることを前提としています。質問は細部に少し軽いので、これについて言及することは少し推測です。

DDLはバージョン管理されていないので、2番目の考慮事項は、ほぼ間違いなく問題とは無関係です。個別のインデックス作成ステートメントにより、SNAPSHOT分離レベルの明示的なトランザクションが失敗します。

4
Paul White 9

解決策ではありませんが、完全を期すために:一時テーブルの計算列にフィルター処理されたインデックスを作成しているときに、SQL 2016で同様の問題が発生しました(手順ではなく、スタンドアロンでも機能します)。

CREATE TABLE #temp_table_name_goes_here (
    [the_first_col] BIGINT NULL
    ,[the_second_col] INT NULL
    ,[another_col] VARCHAR(20) NULL
    , calc AS IIF(the_second_col = 0, 'hello', NULL)
    , INDEX #ix_tmp (calc) WHERE calc IS NOT NULL
    );

SELECT * FROM #temp_table_name_goes_here

SELECTは数回エラー207をスローします:無効な列名 'calc'。

そして最後のエラー4184:

テーブル "#temp_table_name_goes_here"スキーマが頻繁に変更されているため、クエリ操作のテーブルデータを取得できません。テーブル "#temp_table_name_goes_here"にフィルターインデックスまたはフィルター統計が含まれているため、テーブルスキーマを変更するには、すべてのテーブルデータ。クエリ操作を再試行し、問題が解決しない場合は、SQL Serverプロファイラーを使用して、発生しているスキーマ変更操作を特定します。

したがって、一時テーブルのフィルター選択されたインデックスにいくつかの問題があるようです。

インデックスをフィルタリングしないことでこのバグを回避しました(たとえそれが意味する場合でも、大きくなる)

0
Thomas Franz