web-dev-qa-db-ja.com

8000万件のレコードを含むテーブルとインデックスの追加には、18時間(または永久)以上かかります!それで?

起こったことの短い要約。私は7,100万件のレコードを処理しています(他の人が処理した数十億件のレコードとは比べ物になりません)。別の thread で、誰かが私のクラスターの現在のセットアップが私のニーズに適していないことを示唆しました。私のテーブル構造は次のとおりです。

CREATE TABLE `IPAddresses` (
  `id` int(11) unsigned NOT NULL auto_increment,
  `ipaddress` bigint(20) unsigned default NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM;

そして、7,100万件のレコードを追加してから、次のことを行いました。

ALTER TABLE IPAddresses ADD INDEX(ipaddress);

14時間経ちましたが、操作はまだ完了していません。グーグルで、この問題を解決するためのよく知られたアプローチがあることを発見しました-パーティショニング。 ipaddressに基づいてテーブルをパーティション分割する必要があることを理解していますが、テーブル全体を再作成せずにこれを実行できますか?つまり、ALTERステートメントを使用して? 「はい」の場合、パーティション化する列を主キーにする必要があるという要件が1つありました。別のテーブルを作成する際にこのIPアドレスのIDを使用するので、IPアドレスは私の主キーではありません。このシナリオでテーブルをパーティション分割するにはどうすればよいですか?

30
Legend

この問題は、テーブルを作成し、インデックスを作成し、問題を忘れるだけのものではなかったことがわかりました:)誰かが同じ問題に直面した場合に私がしたことはここにありますデータ型も):

問題:テーブルには数百万のエントリがあり、本当に高速にインデックスを追加する必要があります

ユースケース:ルックアップテーブルに数百万のIPアドレスを保存することを検討してください。 IPアドレスの追加は大きな問題にはなりませんが、それらのインデックスの作成には14時間以上かかります。

SolutionMySQLのPartitionin g戦略を使用してテーブルをパーティション分割する

ケース#1:目的のテーブルがまだ作成されていない場合

CREATE TABLE IPADDRESSES(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  ipaddress BIGINT UNSIGNED,
  PRIMARY KEY(id, ipaddress)
) ENGINE=MYISAM
PARTITION BY HASH(ipaddress)
PARTITIONS 20;

ケース#2:必要なテーブルがすでに作成されている場合これを行うためにALTER TABLEを使用する方法があるようですが、私はまだ考えていませんこれに対する適切な解決策を見つけてください。代わりに、わずかに非効率的なソリューションがあります。

CREATE TABLE IPADDRESSES_TEMP(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  ipaddress BIGINT UNSIGNED,
  PRIMARY KEY(id)
) ENGINE=MYISAM;

このテーブルにIPアドレスを挿入します。そして、パーティションを持つ実際のテーブルを作成します。

CREATE TABLE IPADDRESSES(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  ipaddress BIGINT UNSIGNED,
  PRIMARY KEY(id, ipaddress)
) ENGINE=MYISAM
PARTITION BY HASH(ipaddress)
PARTITIONS 20;

そして最後に

INSERT INTO IPADDRESSES(ipaddress) SELECT ipaddress FROM IPADDRESSES_TEMP;
DROP TABLE IPADDRESSES_TEMP;
ALTER TABLE IPADDRESSES ADD INDEX(ipaddress)

そして、新しいテーブルでのインデックス作成には、1GB RAM :)の3.2GHzマシンで約2時間かかりました。これが役に立てば幸いです。

37
Legend

MySQLを使用したインデックスの作成は遅いですが、それほど遅くはありません。 7,100万件のレコードがあるため、14時間ではなく、数分かかります。考えられる問題は次のとおりです。

  • ソートバッファサイズおよびその他の設定オプションを設定していない

こちらをご覧ください: http://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_myisam_sort_buffer_size

8MBのソートバッファーで1GBのインデックスを生成しようとすると、多くのパスが必要になります。ただし、バッファがCPUキャッシュよりも大きい場合、遅くなります。そのため、何が最適かをテストして確認する必要があります。

  • 誰かがテーブルをロックしています
  • あなたのIOシステムは吸う
  • サーバーがスワップしています

通常どおり、iostat、vmstat、logsなどを確認します。テーブルにLOCK TABLEを発行して、誰かがロックを持っているかどうかを確認します。

参考までに、64ビットデスクトップで10MランダムBIGINTのインデックスを作成するには17秒かかります...

8
peufeu

インデックスを追加してクエリを高速化したいという問題がありました。テーブルには約300.000レコードしかありませんでしたが、時間がかかりすぎました。 mysqlサーバープロセスをチェックしたところ、最適化しようとしていたクエリがまだバックグラウンドで実行されていることがわかりました。 4回!これらのクエリを削除した後、インデックス作成はJiffyで行われました。おそらく同じ問題があなたの状況に当てはまります。

5
Giel Berkers

すぐに廃止されるMyISAMを使用しています。代替手段はInnoDBです。

「InnoDBは、ユーザーデータを保護するコミット、ロールバック、クラッシュ回復機能を備えた、MySQL用のトランザクションセーフ(ACID準拠)ストレージエンジンです。InnoDB行レベルロック(より粗い粒度ロックへのエスカレーションなし)およびOracleスタイルの一貫した非ロックInnoDBはユーザーデータをクラスター化インデックスに格納し、主キーに基づく一般的なクエリのI/Oを削減します。データの整合性を維持するために、InnoDBはFOREIGN KEY参照整合性制約もサポートします。同じステートメント内であっても、他のMySQLストレージエンジンのテーブルを使用します。 "\

http://dev.mysql.com/doc/refman/5.0/en/innodb.html

による:

http://dev.mysql.com/tech-resources/articles/storage-engine/part_1.html

、柔軟性を高める単純なalterコマンドを使用して、異なるエンジンを切り替えることができるはずです。また、DB内の各テーブルを個別に構成できることも示しています。

3
Michael Eakins

あなたのテーブルで。すでに710億件のレコードを挿入しています。テーブルのプライマリキー列にパーティションを作成する場合は、alter tableオプションを使用できます。参考のために例を示します。

CREATE TABLE t1 (
    id INT,
    year_col INT
);

ALTER TABLE t1
    PARTITION BY HASH(id)
    PARTITIONS 8;
0
seema