web-dev-qa-db-ja.com

大きなテーブルでの「ユニークインデックスの作成」に時間がかかりすぎる

GHTorrentのデータベースダンプ(GitHubメタデータを含むCSVファイル)を復元しようとしています。 commitsテーブルには891百万行以上、project_commitsには54億行以上あります。これらのテーブルは非常に大きいため、外部キーチェックをオフにしてLOAD DATA INFILEを使用してロードする必要がありました。 MyISAMエンジンを使用しています。テーブルへのレコードのインポートが完了した後、これらのテーブルのインデックスを作成しようとしています。

commitsテーブルに対して次のmysqlコマンドを実行していますが、12時間以上で完了しませんでした。

CREATE UNIQUE INDEX `sha` ON `ghtorrent_restore`.`commits` (`sha` ASC)  COMMENT '';

Commitsテーブルは次のようになります。

enter image description here

遅いインデックス作成に関する他のstackexchangeの質問を読み、my.cnfディレクトリの/etc/mysqlファイルに以下を設定しました。

[mysqld]
bulk_insert_buffer_size=1G
myisam_sort_buffer_size=8G
key_buffer_size=6G
sort_buffer_size=10M

前のコマンドは時間内に終了しなかったので、コンソールからctrl + zを使用して停止する必要がありました。 MySQLワークベンチでテーブルをチェックしましたが、破損しているようには見えませんが、インデックスの長さとして36GBを示しています。

enter image description here

このテーブルのインポートには約25分かかったので、インデックス作成には1時間以上はかからないと思いますが、「create unique index」コマンドを約2時間実行しても進行の兆候はありません。

コマンドを実行すると、mysqldが大量のCPUを使用し、メモリを使用し続けます。 6GBに達した後は、アクティブでなくなり、ほとんど何もしていません。

enter image description here

これは、コマンド(次の図で選択したもの)がmysqlワークベンチからどのように見えるかを示しています。

enter image description here

Mysql 5.7.22-0ubuntu0.16.04.1を16GB RAMのLinux Mint 17.03マシンで実行しています。

私は上級ユーザーではないので、どんな助けも大いに役立ちます。

更新[Wilson H.の提案どおり]:

my.cnfファイル[06/05/2018 01:06]

!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mysql.conf.d/

[mysqld]
secure-file-priv = ""

[mysqld]
bulk_insert_buffer_size=1G
myisam_sort_buffer_size=8G
key_buffer_size=6G
sort_buffer_size=10M

buffercacheに関連する変数

buffer and cache related system variables

Mysqlのインストールで他に何も変更していません。 Mysqldは、システムで使用可能な合計16GBのRAMのうち、テーブルごとに異なるメモリ量を使用します。 mysql以外にCPU /メモリを大量に消費するアプリケーションは実行していません。

興味深い観察:他のテーブルを使用したいくつかのテストでは、行数の増加に対して時間の増加が示されています。傾向は多項式に見えます。

Polynomial increase of time

次の統計は、上の図の最後のmysqlコマンドが実行されている間にキャプチャされました(つまり、テーブル 'projects'のインデックス作成)。

トップ:top

iostat -x:iostat -x

ulimit -a:

ulimit -a

df -h:

df -h

Update 2: 'commits'テーブルでのインデックスの作成が完了していないため、他のテーブルを試し、最後に 'project_commits'テーブルでインデックス付けを試みました昨夜寝る前に。驚いたことに、インデックス作成を完了するのに18分しかかからなかった。

enter image description here

追加の変更は行わず、「コミット」テーブルが終了しない理由がわかりません。 'commits'テーブルで再度インデックス作成を実行して、それがどの程度進んでいるかを確認します。

更新3:

'SHOW CREATE TABLE commits;'

CREATE TABLE `commits` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `sha` varchar(40) DEFAULT NULL,
  `author_id` int(11) DEFAULT NULL,
  `committer_id` int(11) DEFAULT NULL,
  `project_id` int(11) DEFAULT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `commits_ibfk_1` (`author_id`),
  KEY `commits_ibfk_2` (`committer_id`),
  KEY `commits_ibfk_3` (`project_id`)
) ENGINE=MyISAM AUTO_INCREMENT=922093754 DEFAULT CHARSET=utf8

SHOW PROCESSLIST:SHOW PROCESSLIST

ボトムライン:

「コミット」テーブルを除くすべてのテーブルのインデックス作成が完了します(つまり、次のコマンドは実行を完了していません)。

CREATE UNIQUE INDEX `sha` ON `ghtorrent_restore`.`commits` (`sha` ASC)  COMMENT '';

8億9100万行から約19000行をカウントするクエリ(下図を参照)を実行すると、約76秒かかります。 Core i707700HQ CPU @ 2.8 GHz x 4、16 GB DDR4 Ramを搭載したコンピューターがあり、データベースが7200RPMのHDDにインストールされている場合、今回は高すぎますか? 76秒は、 'commits'テーブルでインデックスが正しく機能していないことを示していますか?このクエリは、影響を避けるためにコンピューターの起動直後に実行されたことに注意してくださいバッファから。

enter image description here

4
Narnia_Optimus

複数の問題があります。

922MのAuto_incは、_INT SIGNED_の20億の制限の半分です。次のALTER中に_INT UNSIGNED_(40億制限)に変更することを提案します。

MyISAMはディスク領域を節約しますが、それ以外はInnoDBよりも「悪い」です。注:InnoDBに変更するには、いくつかの設定を変更する必要があります。

MyISAMは_FOREIGN KEYS_を無視します。

shaがSHA-1ハッシュの場合、インデックス作成はひどいです。

shaがSHA-1ハッシュの場合、BINARY(20)を介してUNHEX()に圧縮できます。これにより、テーブルが20GB以上、現在のサイズの30%縮小されます。

shaがSHA-1ハッシュの場合、utf8を使用しないでください。 asciiまたはlatin1を使用します。

shaがSHA-1ハッシュであり、それがUNIQUEインデックスを作成する列である場合は、_SHOW PROCESSLIST_を確認します。 「key_bufferによる修復」と表示されている場合は、強制終了する必要があります。完了するまでか月かかります。 「並べ替え修理中」と表示されていれば終了する見込みです。

著者、コミッター、およびプロジェクトには、4バイトINTよりも小さいIDを使用することを検討してください。待つ!何?これらはそれぞれUNIQUEになりますか?疑わしい。

何をSELECTs持っていますか?それらのいくつかは「複合」インデックスを必要とするのでしょうか?

複数のALTERs(インデックスの作成を含む)を1つのステートメントに入れます。各ALTERは(MyISAM内の)テーブルの完全なコピーです。

_myisam_sort_buffer_size = 8G_はRAMの半分です。これは悪いです。 3Gを提案します。

多項式

傾向は多項式に見えます。

alreadyが_UNIQUE INDEX_と同じ列を持つテーブルの列に_PRIMARY KEY_を追加していないことを願っています。それは完全に冗長になります。そのうちの1つに_SHOW CREATE TABLE_を入力してください。

なぜ「多項式」なのか?もしそうなら(そして私はそのように質問します)、それは "Repair by key_buffer"の性質によるものでしょう:

各行について、すべての一意の(プライマリを含む)インデックスで列を調べ、「重複」していないことを確認します。このルックアップでは、インデックスのBTreeのブロックをフェッチして、テスト用に「key_buffer」に配置する必要があります。キーの「順序」とデータの「順序」に応じて:

  • 行が時系列に挿入された(そしてテーブルがフラグメント化されなかった)auto_incrementまたはtimestampの場合、次に必要なブロックは、直前に処理されたブロックである可能性が非常に高くなります。 I/Oが最小限で済むため、これが最も効率的です。
  • SHA1/MD5/UUID/etcの場合、この検索はインデックス全体をジャンプします。したがって、次に必要なブロックは、RAM内のkey_bufferにある可能性が低くなります。極端な場合、これにより、ルックアップごとにほぼ1つのディスクが読み取られます。
  • 他のインデックスの場合、タイミングはその中間です。
3
Rick James
1
Evan Carroll