web-dev-qa-db-ja.com

テーブルに大きな変更を加えるには、何が良いのでしょうか?毎回DELETEとINSERTまたはUPDATEが存在しますか?

私は、1つのテーブルで毎日約36Kのレコードを変更する必要があるプロジェクトを作成しています。私は何がより良いパフォーマンスをするのだろうと思っています:

  1. 行を削除して新しい行を挿入する、または
  2. 既存の行を更新する

私にとっては、すべての行を削除して新しい行を挿入する方が簡単ですが、これがテーブルとインデックスを断片化してパフォーマンスに影響を与える場合は、可能な限り更新を行い、必要な場合にのみ削除/挿入することをお勧めします。

これは毎晩のサービスになるので、プロセス自体の速度を向上させるつもりはありません。このテーブルに対するクエリのパフォーマンス全般については、すでに8900万件のレコードがあり、この夜間のプロセスがどのように影響するかについて、私はもっと心配しています。

この夜間プロセスのレコードを削除/挿入するか、既存のレコードを(可能な場合)更新する必要がありますか?

27
adopilot

それは実際にどの程度のデータが変化しているかに依存します。このテーブルに20列あるとします。また、5つのインデックスがあり、それぞれが差分にあります。カラム。

20列すべての値が変化している場合OR 5列のデータが変化し、これらの5列にすべてインデックスが付けられている場合でも、「削除して挿入」する方がよいでしょう。ただし、変更されているのは2列のみで、これらは非クラスター化インデックスの一部ではないと言う場合は、レコードを「更新」することをお勧めします。この場合、クラスター化インデックスのみが更新されるため(インデックスを更新する必要がないため) )。


さらに調査したところ、SQL Serverには内部的にUPDATEを実行するための2つの別個のメカニズムがあるため、上記のコメントは冗長であることがわかりました。 -「インプレース更新」(つまり、列の値を元の行の新しい値に変更する)または「非インプレース更新」(DELETEの後にINSERT)。

インプレース更新がルールであり、可能であれば実行されます。ここでは、行は同じページの同じ範囲の同じ位置に正確にとどまります。影響を受けるバイトのみが変更されます。 tlogにはレコードが1つしかありません(更新トリガーがない場合)。ヒープが更新されている(そしてページに十分なスペースがある)場合、更新は適切に行われます。クラスタリングキーが変更されても、行がまったく移動する必要がない場合にも、更新が行われます。

例:姓にクラスター化インデックスがあり、名前がAble、Baker、Charlieの場合次に、BakerをBeckerに更新します。行を移動する必要はありません。したがって、これはインプレースで実行できます。一方、AbleをKumarに更新する必要がある場合は、行をシフトする必要があります(同じページにある場合でも)。この場合、SQL ServerはDELETEに続いてINSERTを実行します。

上記を考慮して、通常のUPDATEを実行し、SQL Serverにそれを内部的に実行する最良の方法を見つけさせることをお勧めします。

"UPDATE"内部の詳細、またはSQL Server関連の内部については、Kalen Delaney、Paul Randalなどの本- SQL Server 2008 Internals を参照してください。

10

SQL 2008で [〜#〜] merge [〜#〜] コマンドを調査しましたか?基本的な例を次に示します。

  merge YourBigTable ybt
  using (select distinct (RecordID) from YourOtherTable) yot
     on yot.Recordid = YBT.RecordID
  when NOT matched by target
  then  insert (RecordID)
        values (yot.DeviceID) ;

これは基本的に「UPSERT」コマンドです。存在する場合は更新し、存在しない場合は挿入します。非常に速く、とてもクールなコマンド。

8
datagod

しかし、私自身が3000万(3クローア)のレコードを持つテーブルで、削除と挿入と更新をチェックしました。このテーブルには、1つのクラスター化された一意の複合キーと3つの非クラスター化キーがあります。削除と挿入の場合、9分かかりました。アップデートには55分かかりました。各行で更新された列は1つだけです。

だから、私はあなたに人々が推測しないようにお願いします。多くの列と多くのデータを持つ大きなテーブルを扱うとき、方程式は変化します。

4
srinivas

更新はそれほど速くありません。秘訣は、高速な挿入を実現することであり、データが挿入されている間はインデックスを無効にします。

これを使用することを検討してください:

-- disable indexes
ALTER INDEX [index_name] ON dbo.import_table DISABLE
-- ... disable more indexes

-- don't use delete if you don't care about minimal logging. truncate is faster
TRUNCATE TABLE dbo.import_table

-- just insert the new rows
INSERT dbo.import_table
SELECT
    *
FROM
    dbo.source_table

-- rebuild indexes
ALTER INDEX [index_name] ON dbo.import_table REBUILD
-- ... rebuild more indexes

さらに高速なのは、dbオプションで統計の自動更新をオフにすることです。テーブルが大幅に変更された場合は、次を実行する必要があります。

UPDATE STATISTICS dbo.import_table

または

EXEC sp_updatestats

統計を最新に保つための定期的なジョブ(毎日、DBサイズに応じて毎週)として。注意すべきことは、テーブルが空のときに統計を更新することです。テーブルに再度データが入力された後で実行しないと、統計が台無しになります。

3
Asken