2

これは冒険でした。前の質問にあるループ重複クエリから始めましたが、各ループは1,700 万レコードすべてを超えるため、数週間かかります(MSSQL 2005 を使用してサーバーを実行するだけで*select count * from MyTable*4:30 分かかります)。私はこのサイトとこの投稿から情報を集めました。

そして、以下のクエリに到達しました。問題は、これがどのタイプのパフォーマンスでも 1,700 万件のレコードに対して実行する正しいタイプのクエリであるかということです。そうでない場合、何ですか?

SQL クエリ:

DELETE tl_acxiomimport.dbo.tblacxiomlistings
WHERE RecordID in 
(SELECT RecordID
    FROM tl_acxiomimport.dbo.tblacxiomlistings
    EXCEPT
    SELECT RecordID
    FROM (
        SELECT RecordID, Rank() over (Partition BY BusinessName, latitude, longitude,           Phone ORDER BY webaddress DESC, caption1 DESC, caption2 DESC ) AS Rank
    FROM tl_acxiomimport.dbo.tblacxiomlistings
    ) al WHERE Rank = 1)
4

11 に答える 11

6

QueryPlanを確認すると役立ちます。

これは実行可能ですか?

SELECT m.*
into #temp
FROM tl_acxiomimport.dbo.tblacxiomlistings m 
inner join (SELECT RecordID, 
                   Rank() over (Partition BY BusinessName, 
                                             latitude,  
                                             longitude,            
                                             Phone  
                                ORDER BY webaddress DESC,  
                                         caption1 DESC,  
                                         caption2 DESC ) AS Rank
              FROM tl_acxiomimport.dbo.tblacxiomlistings
           ) al on (al.RecordID = m.RecordID and al.Rank = 1)

truncate table tl_acxiomimport.dbo.tblacxiomlistings

insert into tl_acxiomimport.dbo.tblacxiomlistings
     select * from #temp
于 2008-10-02T14:38:52.220 に答える
2

DB、サーバー、ストレージ、またはそれらの組み合わせに問題があります。選択カウントの4:30*は非常に高いようです。

DBCC_SHOWCONTIGを実行して、テーブルがどの程度断片化されているかを確認します。これにより、そのサイズのテーブルでパフォーマンスが大幅に低下する可能性があります。

また、RyanKeeterによるコメントに追加するには、show planを実行し、テーブルスキャンがある場合は、そのテーブルのPKフィールドのインデックスを作成します。

于 2008-10-02T14:10:17.453 に答える
2

するのはもっと簡単ではないでしょうか:

DELETE tl_acxiomimport.dbo.tblacxiomlistings
WHERE RecordID in 
(SELECT RecordID
   FROM (
        SELECT RecordID,
            Rank() over (Partition BY BusinessName,
                                  latitude,
                                  longitude,
                                  Phone
                         ORDER BY webaddress DESC,
                                  caption1 DESC,
                                  caption2 DESC) AS Rank
        FROM tl_acxiomimport.dbo.tblacxiomlistings
        )
  WHERE Rank > 1
  )
于 2008-10-02T16:16:47.117 に答える
1

クエリアナライザでこれを実行します。

SET SHOWPLAN_TEXT ON

次に、クエリアナライザにクエリを実行するように依頼します。クエリを実行する代わりに、SQL Serverはクエリプランを生成し、それを結果セットに配置します。

クエリプランを表示します。

于 2008-10-02T13:53:23.157 に答える
1

1,700万件のレコードは何もありません。select count(*)を実行するのに4:30かかる場合は、深刻な問題があります。おそらく、サーバーのメモリ不足または非常に古いプロセッサに関連しています。

パフォーマンスのために、マシンを修正します。2GBまでポンプします。RAMは最近非常に安いので、そのコストはあなたの時間よりはるかに安いです。

そのクエリが実行されているときに、プロセッサまたはディスクがスラッシングしていますか?そうでない場合は、何かが呼び出しをブロックしています。その場合、クリーンアップの実行にかかる時間の間、データベースをシングルユーザーモードにすることを検討してください。

于 2008-10-02T14:04:26.827 に答える
1

最初に一時テーブルを選択するという上記の提案が最善の策です。次のようなものを使用することもできます。

set rowcount 1000

削除を実行する前に。1000行を削除すると、実行が停止します。次に、0レコードが削除されるまで、何度も実行します。

于 2008-10-02T14:10:53.427 に答える
1

では、最初にランク付けされていないすべてのレコードを削除するのですか?結合を上位1つのサブクエリと比較する価値があるかもしれません(ランクは2005以上であるため、2000年でも機能する可能性があります)

1回の操作ですべての重複を削除する必要がありますか?ある種のハウスキーピングタスクを実行していると思いますが、区分的に実行できる可能性があります。

基本的に、すべてのレコードをループし(ダーティリード)、それぞれの重複を削除するカーソルを作成します。全体的にはかなり遅くなりますが、各操作は比較的最小限に抑えられます。そうすれば、ハウスキーピングは毎晩のバッチではなく、一定のバックグラウンドタスクになります。

于 2008-10-02T14:06:09.880 に答える
1

私が正しく取得した場合、クエリは次と同じです

DELETE tl_acxiomimport.dbo.tblacxiomlistings
FROM
    tl_acxiomimport.dbo.tblacxiomlistings allRecords
    LEFT JOIN (   
        SELECT RecordID, Rank() over (Partition BY BusinessName, latitude, longitude, Phone ORDER BY webaddress DESC, caption1 DESC, caption2 DESC ) AS Rank
        FROM tl_acxiomimport.dbo.tblacxiomlistings
        WHERE Rank = 1) myExceptions
    ON allRecords.RecordID = myExceptions.RecordID
WHERE
    myExceptions.RecordID IS NULL

可能であれば、JOIN を優先して "IN" 句の使用を避ける傾向があります。

たとえば、FROM 部分でSELECT *orを呼び出すだけで、実際に速度と結果を安全にテストできます。SELECT COUNT(*)

SELECT *
FROM
    tl_acxiomimport.dbo.tblacxiomlistings allRecords
    LEFT JOIN (   
        SELECT RecordID, Rank() over (Partition BY BusinessName, latitude, longitude, Phone ORDER BY webaddress DESC, caption1 DESC, caption2 DESC ) AS Rank
        FROM tl_acxiomimport.dbo.tblacxiomlistings
        WHERE Rank = 1) myExceptions
    ON allRecords.RecordID = myExceptions.RecordID
WHERE
    myExceptions.RecordID IS NULL

それが、私が JOIN アプローチを好むもう 1 つの理由です。

于 2008-10-02T15:06:37.753 に答える
0

これは問題ないように見えますが、データを一時テーブルに選択し、それをdeleteステートメントで使用することを検討してください。1つのクエリですべてを実行するのではなく、これを実行することでパフォーマンスが大幅に向上することに気付きました。

于 2008-10-02T14:03:32.507 に答える
0

大規模な削除を行うときは、最初に適切なバックアップを作成するのが最善であることを忘れないでください.(また、私は通常、削除されたレコードを別のテーブルにコピーします.念のため、すぐにそれらを回復する必要があります.)

于 2009-07-24T14:48:26.710 に答える
-1

提案されたように切り捨てを使用する以外に、テーブルから多くの行を削除するためにこのテンプレートを使用するのが最善でした。覚えていませんが、トランザクションを使用することで、ログ ファイルが大きくなるのを防ぐことができたと思います。別の理由かもしれませんが、よくわかりません。そして、私は通常、次のようなことを行う前に、トランザクション ログの方法をシンプルに切り替えます。

SET ROWCOUNT 5000
WILE 1 = 1
始める
    トランを開始
            から削除??? どこ ???
            IF @@行数 = 0
            始める
               専念
               壊す
            終わり
    専念
終わり
SET ROWCOUNT 0
于 2008-10-02T19:28:48.967 に答える