6

SQL Server 2005 データベースがあり、数百万行 (列が 3 つしかない)DELETEのテーブルからのレコードの処理を高速化するために、適切なフィールドにインデックスを配置しようとしましたが、実行時間がさらに長くなりました! (例: 1 時間対 13 分)big_tableDELETE

テーブルとの間に関係があり、フィルター処理する列DELETEは他のテーブルにあります。例えば

DELETE FROM big_table
WHERE big_table.id_product IN (
SELECT small_table.id_product FROM small_table
WHERE small_table.id_category = 1)

ところで、私も試しました:

DELETE FROM big_table
WHERE EXISTS
(SELECT 1 FROM small_table
WHERE small_table.id_product = big_table.id_product
AND small_table.id_category = 1)

最初のものよりもわずかに速く実行されているように見えますが、インデックスを使用すると、使用しない場合よりもはるかに遅くなります。

これらのフィールドにインデックスを作成しました。

  1. big_table.id_product
  2. small_table.id_product
  3. small_table.id_category

.ldf ファイルは、.ldf ファイルの実行中に大きくなりDELETEます。

DELETEテーブルにインデックスがあるとクエリが遅くなるのはなぜですか? 彼らはもっと速く走るべきだと思った。

アップデート

DELETEさて、コンセンサスは、インデックスを更新する必要があるため、インデックスが大幅に遅くなるということです。DELETEただし、すべての行を一度にすべて取得できず、最後にインデックスを 1 回だけ更新できない理由はまだわかりません。

私はいくつかの読書から、句DELETE内のフィールドの検索を高速化することでインデックスが高速化されるという印象を受けました。WHERE

Odetocode.com によると:

「インデックスは、SELECT ステートメントの場合と同様に、DELETE および UPDATE コマンドでレコードを検索する場合にも機能します。」

ただし、記事の後半で、インデックスが多すぎるとパフォーマンスが低下する可能性があると述べています。

ボブの質問への回答:

  1. テーブル内の 5,500 万行
  2. 4,200 万行が削除されています
  3. 同様のSELECTステートメントは実行されません (タイプ 'System.OutOfMemoryException' の例外がスローされました)。

次の2つのクエリを試しました:

SELECT * FROM big_table
WHERE big_table.id_product IN (
SELECT small_table.id_product FROM small_table
WHERE small_table.id_category = 1)

SELECT * FROM big_table
INNER JOIN small_table
ON small_table.id_product = big_table.id_product
WHERE small_table.id_category = 1

SQL Server 2005 からの次のエラー メッセージで25 分間実行した後、両方とも失敗しました。

An error occurred while executing batch. Error message is: Exception of type 'System.OutOfMemoryException' was thrown.

データベース サーバーは、7.5 GB RAM を搭載した古いデュアル コア Xeon マシンです。これは私のおもちゃのテストデータベースです:)ので、他には何も実行していません。

CREATEインデックスを適切に機能させるために、インデックスを作成した後に何か特別なことをする必要がありますか?

4

5 に答える 5

29

本の巻末の索引のように、索引は検索を高速化します。

データを変更する操作 (DELETE など) は、インデックスの操作を伴うため、処理が遅くなります。本の後ろにある同じ索引を考えてみましょう。ページを追加、削除、または変更すると、インデックスも更新する必要があるため、さらに多くの作業が必要になります。

于 2010-08-10T22:07:02.017 に答える
3

上記のボブのコメントに同意します-大きなテーブルから大量のデータを削除する場合、データの削除に加えて、インデックスの削除に時間がかかる場合がありますが、ビジネスを行うためのコストがかかります. すべてのデータを削除すると、再インデックス イベントが発生します。

ログファイルの増加に関して; ログファイルで何もしていない場合は、単純なログに切り替えることができます。ただし、変更する前に、IT 部門に与える可能性のある影響についてよくお読みになることをお勧めします。

リアルタイムで削除する必要がある場合。多くの場合、テーブルで直接または別のテーブルで非アクティブとしてデータにフラグを立て、そのデータをクエリから除外することは良い回避策です。後で戻ってきて、ユーザーが砂時計を見つめていないときにデータを削除します。これをカバーする 2 つ目の理由があります。テーブルから大量のデータを削除している場合 (これは、ログファイルの問題に基づいて私が想定しているものです)、おそらく indexdefrag を実行してインデックスを再編成する必要があります。電話でのユーザーが気に入らない場合は、時間外にそれを行うのが最善の方法です。

于 2010-08-11T06:25:53.047 に答える
1

一括削除を回避するために、次のようなことを試してください (それにより、ログ ファイルの増大を回避します)。

declare @continue bit = 1

-- delete all ids not between starting and ending ids
while @continue = 1
begin

    set @continue = 0

    delete top (10000) u
    from    <tablename> u WITH (READPAST)
    where   <condition>

    if @@ROWCOUNT > 0
        set @continue = 1 

end
于 2015-01-14T17:43:42.657 に答える
1

JohnB はデータの約 75% を削除しています。以下は可能な解決策であり、おそらくより高速な解決策の1つだったと思います。データを削除する代わりに、新しいテーブルを作成し、保持する必要があるデータを挿入します。データを挿入した後、その新しいテーブルにインデックスを作成します。ここで、古いテーブルを削除し、新しいテーブルの名前を古いテーブルと同じ名前に変更します。

上記はもちろん、複製されたデータを一時的に保存するのに十分なディスク容量があることを前提としています。

于 2013-03-25T08:58:18.050 に答える
0

DELETE 構文への TSQL 拡張機能を試して、パフォーマンスが向上するかどうかを確認することもできます。

DELETE FROM big_table
FROM big_table AS b
INNER JOIN small_table AS s ON (s.id_product = b.id_product)
WHERE s.id_category  =1
于 2010-08-10T22:27:19.847 に答える