私はデータベースを継承しており、クリーンアップと高速化を目指しています。 30,000,000行を含むテーブルがあります。その多くは、プログラマに代わってエラーが原因で挿入されたジャンクデータです。新しい最適化されたインデックスを追加する前に、テーブルをMyISAMからInnoDBに変換し、ジャンクデータを含む多くの行を削除しようとしています。
データベースはMySQL 5.0であり、サーバーへのrootアクセス権があります。私は最初にこれらのコマンドをAdminerから実行し、次にphpMyAdminを実行しましたが、どちらも同じ結果になりました。
私が実行しているコマンドは、
DELETE
FROM `tablename`
WHERE `columnname` LIKE '-%'
基本的に、この列のダッシュ-
で始まるものはすべて削除してください。
実行時間は約3〜5分ですが、プロセスリストを表示すると、表示されません。
次に走ります
SELECT *
FROM `tablename`
WHERE `columnname` LIKE '-%'
そして何百万もの行を返します。
削除ステートメントが完了しないのはなぜですか?
PS、私はMySQL 5.0がどれほど古いかを知っています。私はDBをMySQL 5.6 w InnoDB(多分MariaDB 10 w XtraDB)に移行する作業をしていますが、それが発生するまで、DBでそのまま答えたいと思っています。
-
編集は削除されました。私の回答を参照してください。
私の場合、必要な答えを過度に複雑にした可能性があります。 RolandとRick Jamesの両方が、フィルタを通過する行のみを挿入する一時テーブルの作成で正しいことは間違いありませんNOT LIKE '-%'
ですが、私が気づいていない重要なエラーがあったため、私にとっての解決策は「簡単」でした今までとそのために私はお詫び申し上げます。
mysql
インタラクティブプロンプトでクエリを実行したところ、エラーメッセージが表示されました。
mysql> DELETE FROM `slugs` WHERE `slug` LIKE '-%';
ERROR 1206 (HY000): The total number of locks exceeds the lock table size
エラーのグーグル化を通じて、私は 解決策を見つけました は、innodb_buffer_pool_size
ファイルを介して/etc/my.cnf
を増やし、mysqlデーモンを再起動することでした。私のサーバーでは、デフォルトの8M
に設定され、1G
に増やしました(サーバーには32GBがあり、これは現在InnoDBにある唯一のテーブルです)。
mysql> DELETE FROM `slugs` WHERE `slug` LIKE '-%';
Query OK, 23517226 rows affected (27 min 33.23 sec)
その後、コマンドを実行して、約27分で2,300万件のレコードを削除することができました。
何がinnodb_buffer_pool_size
に設定する必要があるのか知りたい場合は、RAMをどれだけ持っているかをメモしてから、 このスレッドを見てください GBでの見積もり。
InnoDBのアーキテクチャをご覧ください(Percona CTO Vadim Tkachenkoの写真)
削除する行は、元に戻すログに書き込まれています。削除の期間中、ファイルibdata1は現在増加しているはずです。 mysqlperformanceblog.comのReasons for run-away main Innodb Tablespace
:
あなたの場合、行を削除しているので、理由#1はいくつかの取り消しスペースと共に1つのロールバックセグメントを占有します。これらの行は、削除が完了するまでibdata1に存在する必要があります。そのスペースは論理的に破棄されますが、ディスクスペースは縮小されません。
今すぐその削除を強制終了する必要があります。削除クエリを強制終了すると、削除された行がロールバックされます。
代わりにこれを行います:
CREATE TABLE tablename_new LIKE tablename;
INSERT INTO tablename_new SELECT * FROM tablename WHERE `columnname` NOT LIKE '-%';
RENAME TABLE
tablename TO tablename_old,
tablename_new TO tablename
;
DROP TABLE tablename_old;
最初に、テーブルのMyISAMバージョンに対してこれを行うことができます。次に、それをInnoDBに変換します。
ローランドの提案は、両方のことを一度に行うことによって、いくつかをスピードアップすることができます:
CREATE TABLE tablename_new LIKE tablename;
ALTER TABLE tablename_new ENGINE = InnoDB;
INSERT INTO tablename_new
SELECT * FROM tablename WHERE `columnname` NOT LIKE '-%' ORDER BY primary_key;
RENAME TABLE
tablename TO tablename_old,
tablename_new TO tablename
;
DROP TABLE tablename_old;
しかし、これは一見永久にかかるのではなく、チャンクで大きなDELETEを行う方法を説明するブログです: http://mysql.rjweb.org/doc.php/deletebig 要点は、 PKを介してテーブルを作成し、一度に1K行を実行します。 (もちろん、注意すべき詳細事項があります。)
そして、このブログは、InnoDBへの変換における潜在的な問題に対処しています: http://mysql.rjweb.org/doc.php/myisam2innodb
私の最初の本能は、クエリ結果の数を制限し、クエリを複数回実行することにより、複数のより小さな削除を実行することです:
DELETE
FROM `tablename`
WHERE `columnname` LIKE '-%' LIMIT 1000000
最も簡単な解決策は、単純にそれを行わないことです-より簡単に処理できる、より小さな削除を実行します。
この場合、フォームの順次削除を試すことをお勧めします。
DELETE
FROM `tablename`
WHERE `columnname` LIKE '-a%'
多分あなたはこのようなことをすることができます:
deleted
という新しいフィールドを追加します。UPDATE tablename SET deleted=1 WHERE `columnname` LIKE '-a%'
のような更新を行います。cron
を設定します。