3

私は mysql を使用しており、10,000 のブロックで 4 つの部分の主キーを持つ非常に大きなテーブルを処理したいと考えています (別のシステムへのデータのマーシャリング)。処理中はデータベースがオフラインなので、変更について心配する必要はありません。主キーが ( ABCD) であり、すべて整数であるとします。私は最初LIMIT OFFSETにこのようにこれを達成するために使用しようとしました:

SELECT * FROM LargeTable ORDER BY (A, B, C, D) LIMIT 10000 OFFSET 0;

各呼び出しでオフセットを 10000 ずつ増やしました。これは、テーブルの上位の行に近づくにつれて非常に遅くなるように見えました。これをLIMIT OFFSET効率的に行うことはできませんか?

次に、複合主キーの比較を使用する別のアプローチを試しました。次のように最初のブロックを取得できます。

SELECT * FROM LargeTable ORDER BY (A, B, C, D) LIMIT 10000;

そのブロックの最後の行に , , が含まれている場合A = aB = bC = cD = dブロックを取得できます。

SELECT * FROM LargeTable
WHERE
    A > a OR
    (A = a AND B > b) OR
    (A = a AND B = b AND C > c) OR
    (A = a AND B = b AND C = c AND D > d)
ORDER BY (A, B, C, D) LIMIT 10000;

そして、ブロックごとにそれを繰り返します。これも、テーブルの上位の行に到達するにつれて大幅に遅くなるように見えました。これを行うより良い方法はありますか?明らかな何かが欠けていますか?

4

4 に答える 4

3

プレーンなものを使用して最初からデータの処理を開始する

SELECT *
FROM LargeTable
ORDER BY (A, B, C, D)

クライアント コードで行を 1 つずつフェッチします。必要に応じて、フェッチ ループで 10000 行をフェッチするか、LIMIT 10000句を追加できます。このブロックを停止したい場合は、処理された最後のタプル (A、B、C、D) を思い出して、それを呼び出しましょう(A1, B1, C1, D1)

ここで、最後のポイントから再開する場合は、行を 1 つずつフェッチしますが、今回は WHERE 句でタプル比較を使用します。

SELECT *
FROM LargeTable
WHERE (A, B, C, D) > (A1, B1, C1, D1)
ORDER BY (A, B, C, D)

LIMIT 10000(クライアントコードがフェッチループを途中で終了することに依存したくない場合は、句を追加することもできます)。このソリューションの鍵は、MySQL がタプル比較を正しく実装していることです。

編集:オプションLIMIT 10000を追加できると述べました。

于 2012-11-03T21:16:18.100 に答える
1

おそらく、何らかの方法でテーブルの順次スキャンを呼び出しています。

さらに、条件付きのSELECTは、あなたが思っていることをしていません。最初の条件A > aで短絡しています。

ORDER BYLIMITをスキップして、次のようなステートメントを使用すると、より効率的になります。

SELECT *
FROM LargeTable
WHERE A = a AND B = b AND C = c;

そして、 ab、およびcのセットを繰り返すだけです。

于 2012-11-03T21:11:41.957 に答える
0

「マーシャリング」操作を行っているコンテキストに大きく依存しますが、制約のない SELECT を実行させず、コードで 10,000 アイテムのブロックにグループ化することができない理由はありますか?

擬似コード:

while (fetch_row succeeds)
{
    add row to marshalled data
    if (10,000 rows marshalled)
    {
        process 10,000 marshalled rows
        set number of marshalled rows to 0
    }
}
if (marshalled rows > 0)
{
    process N marshalled rows
}
于 2012-11-03T21:10:09.377 に答える
0

Limit with offset は、実際に必要な行が見つかるまで行を破棄する必要があるため、オフセットが大きいほど遅くなります。

これがアイデアです。これを行っている間はデータベースがオフラインであるため、ジョブ中にデータが実際に存在する必要はありません。処理中にすべての処理された行を別のテーブルに移動しないのはなぜですか? テーブルにあるインデックスの数にもよりますが、試してみてください。

CREATE TABLE processed AS LargeTable;

SELECT * FROM LargeTable LIMIT 10000;
INSERT INTO processed SELECT * FROM LargeTable LIMIT 10000;
DELETE FROM LargeTable LIMIT 10000;

DELETE TABLE LargeTable;
RENAME TABLE processed TO LargeTable;
于 2012-11-03T21:45:24.513 に答える