web-dev-qa-db-ja.com

SQLの削除ステートメントが非常に遅い

タイムアウトしているこのようなステートメントがあります:

DELETE FROM [table] WHERE [COL] IN ( '1', '2', '6', '12', '24', '7', '3', '5')

私はこのように一度に1つやってみました:

DELETE FROM [table] WHERE [COL] IN ( '1' )

そして今のところ、それは22分でまだ続いています。

テーブルには260,000行があり、4列です。

なぜこれがとても遅いのか、どのようにスピードアップするのか、誰にもアイデアがありますか? WHEREを実行している[COL]に一意ではない非クラスター化インデックスがあります。 SQL Server 2008 R2を使用しています

更新:テーブルにトリガーがありません。

66
Kyle

削除が遅くなる原因:

  • 多くのレコードを削除する
  • 多くのインデックス
  • 子テーブルの外部キーにインデックスがありません。 (コメントでこれについて言及してくれた@CesarAlvaradoDiazに感謝)
  • デッドロックとブロッキング
  • トリガー
  • カスケード削除(削除する10個の親レコードは、何百万もの子レコードが削除されることを意味します)
  • 成長する必要があるトランザクションログ
  • チェックする多くの外部キー

したがって、あなたが選択できるのは、何がブロックされているかを見つけて修正するか、通常の運用負荷に干渉しない時間外に削除を実行することです。削除はバッチで実行できます(トリガー、カスケード削除、または多数のレコードがある場合に便利です)。インデックスを削除して再作成できます(営業時間外でもできる場合に最適)。

73
HLGEM
  1. 制約を無効にする

    ALTER TABLE [TableName] NOCHECK CONSTRAINT ALL;

  2. インデックスを無効にする

    ALTER INDEX ALL ON [TableName] DISABLE;

  3. インデックスを再構築

    ALTER INDEX ALL ON [TableName] REBUILD;

  4. 制約を有効にする

    ALTER TABLE [TableName] CHECK CONSTRAINT ALL;

  5. もう一度削除

49
Shahab J

多くの行を削除すると、非常に遅くなる可能性があります。次のように、一度にいくつか削除してください。

delete top (10) YourTable where col in ('1','2','3','4')
while @@rowcount > 0
    begin
    delete top (10) YourTable where col in ('1','2','3','4')
    end
18
Andomar

予防措置

この問題の根本的な原因については、SQL Profilerのヘルプを参照してください。 Triggersが実行の遅延を引き起こす可能性があります。何でも構いません。 Traceの開始中にDatabase NameObject Nameを選択して、不要なクエリのスキャンを除外することを忘れないでください...

データベース名フィルタリング

テーブル/ストアドプロシージャ/トリガー名のフィルタリング

是正措置

前にも述べたように、テーブルには260,000件のレコードが含まれており、IN Predicateには6つの値が含まれています。現在、各レコードはIN Predicateの各値に対して260,000回検索されています。代わりに、次のような内部結合にする必要があります...

Delete K From YourTable1 K
Inner Join YourTable2 T on T.id = K.id

IN Predicate値をTemporary TableまたはLocal Variableに挿入します

4
user1425057

削除元のテーブルにBEFORE/AFTER DELETEトリガーがある場合、そこにあるものが遅延の原因である可能性があります。

さらに、そのテーブルを参照する外部キーがある場合、追加のUPDATEまたはDELETEが発生する可能性があります。

3
sybkar

他のテーブルに[テーブル]へのFK制約がある可能性があります。したがって、DBはこれらのテーブルをチェックして、参照整合性を維持する必要があります。これらのFKに対応する必要なインデックスがすべてある場合でも、それらの量を確認してください。

NHibernateが誤って同じ列にduplicated FK sを作成したが、異なる名前(SQL Serverで許可されている)で作成された状況がありました。 DELETEステートメントの実行が大幅に遅くなりました。

2
flam3

私の場合、データベースの統計が壊れていました。声明

delete from tablename where col1 = 'v1' 

一致するレコードがなくても30秒かかっていましたが、

delete from tablename where col1 = 'rubbish'

すぐに走った

ランニング

update statistics tablename

問題を修正しました

1
Mike

選択した数個ではなくテーブル内のすべてのレコードを削除する場合は、テーブルを削除して再作成する方がはるかに高速です。

0
lastlink

[COL]は本当に数値を保持する文字フィールドですか、それとも値を囲む単一引用符を取り除くことができますか? @AlexはINが=より遅いことは正しいので、これを行うことができれば、より良い結果が得られます。

DELETE FROM [table] WHERE [COL] = '1'

ただし、文字列ではなく数字を使用して行を検索する方が良いです(SQLは数字が好きです)。

 DELETE FROM [table] WHERE [COL] = 1

たぶん試してください:

 DELETE FROM [table] WHERE CAST([COL] AS INT) = 1

どちらの場合でも、テーブルスキャンを高速化するために、列[COL]にインデックスがあることを確認してください。

0
Russell Fox

私はこの記事を読んで、それはあらゆる種類の不便をトラブルシューティングするのに本当に役に立ちました

https://support.Microsoft.com/en-us/kb/22445

これは、waitresource KEYの場合です:16:72057595075231744(ab74b4daaf17)

-- First SQL Provider to find the SPID (Session ID)

-- Second Identify problem, check Status, Open_tran, Lastwaittype, waittype, and waittime
-- iMPORTANT Waitresource select * from sys.sysprocesses where spid = 57

select * from sys.databases where database_id=16

-- with Waitresource check this to obtain object id 
select * from sys.partitions where hobt_id=72057595075231744

select * from sys.objects where object_id=2105058535
0
Eduardo

この削除ステートメントの実行計画を確認してください。インデックスシークを使用する場合は、ご覧ください。また、colのデータ型は何ですか?

間違ったデータ型を使用している場合は、更新ステートメントを変更します(「1」から「1」または「N」「1」など)。

インデックススキャンを使用する場合は、いくつかの クエリヒント ..

0
Jānis

私がこれを書いている時間の約5-4年前に私たちのクライアントにセットアップされたSSISパッケージ(SQL Serverのコマンド実行が本当に遅いため)を検査した後、私は以下のタスクがあることがわかりました:1 )XMLファイルから[Importbarcdes]というテーブルにデータを挿入します。

2)上記のテーブルをソースとして使用して、別のターゲットテーブルでコマンドをマージします。

3)「[Importbarcodes]から削除」、SSISパッケージのタスクによってXMLファイルが読み取られた後に挿入された行のテーブルをクリアします。

1行しかないテーブルImportBarcodesのすべてのステートメント(SELECT、UPDATE、DELETEなど)をすばやく検査した後、実行に約2分かかりました。

拡張イベントでは、PAGEIOLATCH_EXの待機通知が大量に表示されました。

テーブルのインデックスが存在せず、トリガーも登録されていません。

テーブルのプロパティを詳細に調べると、[ストレージ]タブの[一般]セクションで、[データスペース]フィールドに6ギガバイトを超えるスペースがページに割り当てられていることが示されました。

どうした:

クエリは過去4年間毎日毎日かなりの時間実行され、テーブル内のデータを挿入および削除し、未使用のページファイルを残してそれらを解放しました。

そのため、これが、拡張イベントセッションによってキャプチャされた待機イベントと、テーブルでゆっくり実行されるコマンドの主な理由でした。

ALTER TABLE ImportBarcodes REBUILDを実行すると、すべての未使用領域が解放される問題が修正されました。 TRUNCATE TABLE ImportBarcodesは同様のことを行いましたが、すべてのページファイルとデータを削除するという唯一の違いがありました。

0
jimas13