4

私は非常に大規模なデータベース(〜100Gb)を持っており、主にサイズを縮小したい2つのテーブルで構成されています(どちらも約5,000万レコードあります)。同じスキーマを使用して、これら2つのテーブルを使用して同じサーバー上にアーカイブDBをセットアップしています。ライブデータベースから行を削除してアーカイブDBに挿入するための最良の概念的な方法を決定しようとしています。擬似コードでは、これは私が今していることです:

Declare @NextIDs Table(UniqueID)
Declare @twoYearsAgo = two years from today's date

Insert into @NextIDs 
     SELECT top 100 from myLargeTable Where myLargeTable.actionDate < twoYearsAgo

Insert into myArchiveTable
<fields>
SELECT <fields> 
FROM myLargeTable INNER JOIN @NextIDs on myLargeTable.UniqueID = @NextIDs.UniqueID

DELETE MyLargeTable
FROM MyLargeTable INNER JOIN @NextIDs on myLargeTable.UniqueID = @NextIDs.UniqueID

現在、これは1000レコードを完了するのに恐ろしく遅い7分かかります。削除と挿入をテストしましたが、どちらも約1時間かかります。完了するまでに3.5分かかるため、必ずしも一方が他方よりも大幅に非効率的であるとは限りません。誰かがこれでいくつかの最適化のアイデアを指摘できますか?

ありがとう!

これはSQLServer2000です。

編集:大きなテーブルでは、ActionDateフィールドにクラスター化されたインデックスがあります。他に2つのインデックスがありますが、どちらもどのクエリでも参照されていません。アーカイブテーブルにはインデックスがありません。私のテストサーバーでは、これがSQL Serverにヒットする唯一のクエリであるため、十分な処理能力が必要です。

コード(これは一度に1000レコードのバッチでループを実行します):

 DECLARE @NextIDs TABLE(UniqueID int primary key)
DECLARE @TwoYearsAgo datetime
SELECT @TwoYearsAgo = DATEADD(d, (-2 * 365), GetDate())

WHILE EXISTS(SELECT TOP 1 UserName FROM [ISAdminDB].[dbo].[UserUnitAudit] WHERE [ActionDateTime] < @TwoYearsAgo)
BEGIN

BEGIN TRAN

--get all records to be archived
INSERT INTO @NextIDs(UniqueID)
        SELECT TOP 1000 UniqueID FROM [ISAdminDB].[dbo].[UserUnitAudit] WHERE [UserUnitAudit].[ActionDateTime] < @TwoYearsAgo

--insert into archive table
INSERT INTO [ISArchive].[dbo].[userunitaudit] 
(<Fields>)
SELECT  <Fields>
FROM  [ISAdminDB].[dbo].[UserUnitAudit] AS a
        INNER JOIN @NextIDs AS b ON a.UniqueID = b.UniqueID

--remove from Admin DB
DELETE [ISAdminDB].[dbo].[UserUnitAudit] 
FROM  [ISAdminDB].[dbo].[UserUnitAudit] AS a
INNER JOIN @NextIDs AS b ON a.UniqueID = b.UniqueID 

DELETE FROM @NextIDs

COMMIT

END
4

6 に答える 6

4

挿入/削除コマンドを実行する前に実行する必要がある3つの選択が事実上あります。

最初の挿入の場合:

SELECT top 100 from myLargeTable Where myLargeTable.actionDate < twoYearsAgo

2番目の挿入の場合:

SELECT <fields> FROM myLargeTable INNER JOIN NextIDs 
on myLargeTable.UniqueID = NextIDs.UniqueID

削除の場合:

(select *)
FROM MyLargeTable INNER JOIN NextIDs on myLargeTable.UniqueID = NextIDs.UniqueID

私はこれらを最適化しようとしますが、それらがすべて速い場合は、インデックスによって書き込みが遅くなる可能性があります。いくつかの提案:

  1. プロファイラーを起動し、読み取り/書き込みなどで何が起こっているかを確認します。

  2. 3つのステートメントすべてのインデックスの使用法を確認してください。

  3. PKのみを返すように実行してSELECTs、遅延がクエリの実行なのかデータのフェッチなのかを確認してください(たとえば、フルテキストインデックス付きのフィールドやTEXTフィールドなどがあります)。

于 2009-12-09T20:15:23.560 に答える
4

結果のフィルタリングに使用している列のソーステーブルにインデックスがありますか?この場合、それはactionDateになります。

また、大規模な挿入を実行する前に、宛先テーブルからすべてのインデックスを削除すると役立つことがよくありますが、この場合、一度に実行するのは100のみです。

また、これをより大きなバッチで行う方がおそらく良いでしょう。一度に100を使用すると、クエリのオーバーヘッドがコスト/時間の大半を占めることになります。

この間、サーバー上で他のアクティビティはありますか?ブロッキングが発生していますか?

うまくいけば、これはあなたに出発点を与えるでしょう。

使用している正確なコードを提供できれば(プライバシーの問題がある場合は列名なしで)、誰かが他の最適化方法を見つけることができるかもしれません。

編集:コードブロックのクエリプランを確認しましたか?このようなテーブル変数で問題が発生しました。クエリオプティマイザーは、テーブル変数のサイズが小さいことを認識できなかったため、常にベーステーブルで全表スキャンを実行しようとしました。

私の場合、それは最終的に論点になったので、最終的な解決策が何であるかはわかりません。確かに、actionDateの条件をすべての選択クエリに追加できます。これにより、少なくともこの影響を最小限に抑えることができます。

もう1つのオプションは、通常のテーブルを使用してIDを保持することです。

于 2009-12-09T20:17:56.570 に答える
1

myLargeTable.actionDateと.UniqueIDにインデックスはありますか?

于 2009-12-09T20:14:10.553 に答える
1

100より大きいバッチサイズを試しましたか?

最も時間がかかっているのは何ですか?INSERT、またはDELETE?

于 2009-12-09T20:15:18.133 に答える
1

INSERTステートメントとDELETEステートメントが結合しています

[ISAdminDB].[dbo].[UserUnitAudit].UniqueID

これにインデックスがなく、インデックスがないことを示している場合は、2回のテーブルスキャンを実行しています。これが速度低下の原因である可能性があります。b/caSQLServerテーブルスキャンは、テーブル全体をスクラッチテーブルに読み込み、スクラッチテーブルで一致する行を検索してから、スクラッチテーブルを削除します。

にインデックスを追加する必要があると思いますUniqueID。それを維持するためのパフォーマンスへの影響は、テーブルスキャンよりも少なくなければなりません。そして、アーカイブが完了した後にそれをドロップすることができます。

于 2009-12-09T20:40:31.437 に答える
0

output句を使用してこれを実行してみてください。

declare @items table (
  <field list just like source table> )

delete top 100 source_table
  output deleted.first_field, deleted.second_field, etc
  into @items
  where <conditions>

insert archive_table (<fields>)
  select (<fields>) from @items

また、アーカイブテーブルに直接'output into'を実行することで、単一のクエリでこれを実行できる場合があります(テーブルvarの必要性を排除します)。

于 2009-12-09T20:39:08.797 に答える