web-dev-qa-db-ja.com

チャンクでテーブルから削除

400万のテーブルの1つをクリーンアップしたいと思います。だから私はそれをきれいにするためにこのクエリを準備します。しかし、それはエラーを投げています、誰かがこれを修正するのを手伝ってくれませんか?

DELIMITER $$
DROP PROCEDURE IF EXISTS archive_table $$
create procedure archive_table () 
set @min=(select min(dob) from test
              where dob < DATE_SUB(CURDATE(), INTERVAL 30 day));
while @min is not null
begin   
    delete from test where dob = @min;
    commit ;
    select min(dob) from test
            where dob > @min
              and dob < DATE_SUB(CURDATE(), INTERVAL 30 day) );
END WHILE;
END$$

エラー:

    ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use
 near 'while @min is not null
begin
    delete from test where dob = @min;
    commi' at line 1
2
Bhuvanesh

手続きBEGINがありません。

チャンクでの削除については、 http://mysql.rjweb.org/doc.php/deletebig#deleting_in_chunks を参照してください

400万行の場合、削除ごとにおそらく13万3千行があります。これは、dobで始まるインデックスがある場合でも、InnoDBを窒息させます。削除を一度に1000以下に減らす方法については、上記のリンクを参照してください。 (1Kはより文明的なチャンクです。)

1
Rick James

Shlomi Noach によるopenarkキットは、まさにあなたの路地にあります!

はじめに ここ

  • Oak-chunk-update:自動管理された小さなチャンクで、長い非ブロッキングUPDATE/DELETE操作を実行します。

ドキュメントページから ここ

このユーティリティを使用すると、実行時間の長い、またはインデックス付けされていないUPDATE/DELETE操作を分割できます。オプションで複数テーブルの操作を分割することもできます。実行時間の長い更新クエリがよく使用されます。いくつかの例:

Purging old table records (e.g. purging old logs).
Updating a column on a table scale.
Deleting or updating a small number of rows, but with a non-indexed search condition.
Inserting into one table aggregated values from other tables.

ツールには、例付きのオプションのloadがあります-さまざまなツールにいくつかのツールを使用したとき、私は非常に感銘を受けました。

それで、午前03:00にcronで開始してリラックスしてください!

2
Vérace

これはあなたが望むことをするかもしれません。これは、非常に大きなテーブルから古い行を削除する方法であり、通常のDELETEのようにデータベースに大きな負荷をかけることはありません

DROP PROCEDURE IF EXISTS archive_table;

DELIMITER $$

CREATE PROCEDURE archive_table()

BEGIN   
    REPEAT
        DO SLEEP(1); ## Optional, to minimise contention
        DELETE FROM test 
        WHERE dob < NOW() - INTERVAL 1 MONTH 
        ORDER BY primary_key 
        LIMIT 1000; ## 10000 also works, this is more conservative      
    UNTIL ROW_COUNT() = 0 END REPEAT;
END$$

DELIMITER ;

CALL archive_table();
0
Silas Palmer

なぜループしているのか混乱しています。バッチを削除して結果を返したいようです。あなたが欲しいのはこのようなものです。

CREATE TEMPORARY TABLE foo
AS
  SELECT *
  FROM test
  WHERE dob < DATE_SUB(CURDATE(), INTERVAL 30 day);

DELETE
FROM test
INNER JOIN foo
  ON (foo.dob = test.dob);

SELECT *
FROM foo;

またはDELETE .. RETURNING をサポートする実際のデータベースを使用します

結果が気にならない場合は、

DELETE
FROM test
WHERE dob < DATE_SUB(CURDATE(), INTERVAL 30 day);
0
Evan Carroll