タイムアウトしているこのようなステートメントがあります:
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を使用しています
更新:テーブルにトリガーがありません。
削除が遅くなる原因:
したがって、あなたが選択できるのは、何がブロックされているかを見つけて修正するか、通常の運用負荷に干渉しない時間外に削除を実行することです。削除はバッチで実行できます(トリガー、カスケード削除、または多数のレコードがある場合に便利です)。インデックスを削除して再作成できます(営業時間外でもできる場合に最適)。
制約を無効にする
ALTER TABLE [TableName] NOCHECK CONSTRAINT ALL;
インデックスを無効にする
ALTER INDEX ALL ON [TableName] DISABLE;
インデックスを再構築
ALTER INDEX ALL ON [TableName] REBUILD;
制約を有効にする
ALTER TABLE [TableName] CHECK CONSTRAINT ALL;
もう一度削除
多くの行を削除すると、非常に遅くなる可能性があります。次のように、一度にいくつか削除してください。
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
予防措置
この問題の根本的な原因については、SQL Profiler
のヘルプを参照してください。 Triggers
が実行の遅延を引き起こす可能性があります。何でも構いません。 Trace
の開始中にDatabase Name
とObject 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
に挿入します
削除元のテーブルにBEFORE/AFTER DELETEトリガーがある場合、そこにあるものが遅延の原因である可能性があります。
さらに、そのテーブルを参照する外部キーがある場合、追加のUPDATEまたはDELETEが発生する可能性があります。
他のテーブルに[テーブル]へのFK制約がある可能性があります。したがって、DBはこれらのテーブルをチェックして、参照整合性を維持する必要があります。これらのFKに対応する必要なインデックスがすべてある場合でも、それらの量を確認してください。
NHibernateが誤って同じ列にduplicated FK sを作成したが、異なる名前(SQL Serverで許可されている)で作成された状況がありました。 DELETEステートメントの実行が大幅に遅くなりました。
私の場合、データベースの統計が壊れていました。声明
delete from tablename where col1 = 'v1'
一致するレコードがなくても30秒かかっていましたが、
delete from tablename where col1 = 'rubbish'
すぐに走った
ランニング
update statistics tablename
問題を修正しました
選択した数個ではなくテーブル内のすべてのレコードを削除する場合は、テーブルを削除して再作成する方がはるかに高速です。
[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]にインデックスがあることを確認してください。
私はこの記事を読んで、それはあらゆる種類の不便をトラブルシューティングするのに本当に役に立ちました
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
この削除ステートメントの実行計画を確認してください。インデックスシークを使用する場合は、ご覧ください。また、colのデータ型は何ですか?
間違ったデータ型を使用している場合は、更新ステートメントを変更します(「1」から「1」または「N」「1」など)。
インデックススキャンを使用する場合は、いくつかの クエリヒント ..
私がこれを書いている時間の約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
は同様のことを行いましたが、すべてのページファイルとデータを削除するという唯一の違いがありました。