Mysql:14億のレコードにインデックスを作成する


9

14億レコードのテーブルがあります。テーブルの構造は次のとおりです。

CREATE TABLE text_page (
    text VARCHAR(255),
    page_id INT UNSIGNED
) ENGINE=MYISAM DEFAULT CHARSET=ascii

要件は、列にインデックスを作成することtextです。

テーブルサイズは約34Gです。

次のステートメントでインデックスを作成しようとしました。

ALTER TABLE text_page ADD KEY ix_text (text)

10時間待った後、ようやくこのアプローチをやめました。

この問題に対して実行可能な解決策はありますか?

UPDATE:テーブルが更新、挿入、または削除されることはほとんどありません。列にインデックスを作成する理由textは、この種のSQLクエリが頻繁に実行されるためです。

SELECT page_id FROM text_page WHERE text = ?

更新:テーブルをパーティション分割することで問題を解決しました。

テーブルは、列で40個に分割されていますtext。その後、テーブルにインデックスを作成すると、完了するまでに約1時間かかります。

テーブルのサイズが非常に大きくなると、MySQLインデックスの作成が非常に遅くなるようです。また、パーティション化により、テーブルがより小さなトランクに縮小されます。


1
通常のCREATE INDEXステートメントを使用することの何が問題になっていますか?

この質問はServerFaultの方がよいかもしれません-プログラミングの質問よりもDB管理者の質問です。
ここから

@Derk:通常のCREATE INDEXアプローチは遅すぎます。1日以内にタスクを完了する必要があります。

1
うーん...あなたはこれを回避できるとは思わない。インデックスを作成するには、DBMSがすべてのレコードをスキャンし、それらの「テキスト」フィールドを収集して、対応するツリーノード/サブツリーを挿入/変更する必要があります。そして、これには34Gにかなりの時間がかかります...
チッコドロ

DBサーバーにはどのくらいのメモリがありますか?そのすべてのメモリを使用するようにMySQLを設定しましたか、それともそれ自体を制限していますか?

回答:


4

それはあなたのシステムがタスクに達していないだけでしょうか?私はMySQL(ここではSQL Server)を使用していませんが、8億のエントリテーブルにインデックスを付けるのは苦痛です。基本的に...あなたはそのための適切なハードウェアを必要とします(例:多くの高速ディスク)。私は今、およそ12のヴェロキラプトルを使用しており、パフォーマンスは素晴らしいです;)

SQLサーバー(MS SQLサーバーとしてではなく、SQLを使用するデータベースサーバーとして)は、ディスクアクセスで稼働し、停止します。通常のディスクは、より大規模な操作のタスクには対応できません。


レコード数が少ない場合、通常、インデックスの作成は非常に高速であることに疑問があります。何百万と言います。しかし、数が数十億になると、インデックスの作成が非常に遅くなります。時間の増加は指数関数的であるようです。

本当にないはずです。MySQLには一般に制限がありますが、それはがらくたのデータベースではありません、そしてそれは非常に悪いでしょう。インデックスの生成は遅くなりますが、(n)ではなくlog(n)によって行われるため、それほど悪いことではありません。
TomTom

4

テキストフィールドの最初の文字(たとえば、10文字)にインデックスを作成することができます。

ドキュメントから:

col_name(length)構文を使用してインデックスプレフィックス長を指定し、列値の先頭部分のみを使用するインデックスを作成できます。

CREATE INDEX ix_text ON text_page (text(10))

4

テーブルを分割することで問題を解決しました。

テーブルは、列で40個に分割されていますtext。その後、テーブルにインデックスを作成すると、完了するまでに約1時間かかります。

テーブルのサイズが非常に大きくなると、MySQLインデックスの作成が非常に遅くなるようです。また、パーティション化により、テーブルがより小さなトランクに縮小されます。


では、40 x 1時間は10時間未満ですか?
symcbean

3

sort_buffer_sizeを4GBに設定します(または、使用しているメモリの量に応じて、どれだけでも可能です)。

現在、作成インデックスはソートを実行していますが、32MBのsort_buffer_sizeがあるため、基本的にハードドライブを不必要にスラッシュしています。


これらの投稿は、あなたとほとんど直接反対しています:xaprb.com/blog/2010/05/09/how-to-tune-mysqls-sort_buffer_sizeとより良い ronaldbradford.com/blog/… それはグローバルな価値ではないようです、それはクエリごとなので、推奨するクエリごとに4GBです。また、256Kを超えると、実際のメモリ内メモリではなく、ディスクにmemマップされます。小さく保つと、複数のパスが必要になりますが、ディスクは回避されます(スワップされません)。
Ry4an Brase

3

次のようなクエリを実行する必要がない場合:

SELECT page_id FROM text_page WHERE text LIKE '?%';

新しいハッシュ列を作成し、列ごとにテーブルにインデックスを付けることをお勧めします。テーブル+インデックスの全体的なサイズははるかに小さい可能性があります。

UPD:ちなみに、14億の主キー整数は約6 GBを占めます。つまり、文字列の平均の長さは30文字未満です。つまり、プレフィックスにインデックスを付ける方が望ましい場合があります。

また、MERGEストレージエンジンも確認する必要があります。


2

これを行う1つの方法は、インデックスセットを使用して新しいテーブルを作成し、データを新しいテーブルにコピーすることです。

また、十分な一時スペースがあることを確認してください。


1
私はこのアプローチを試しました。10時間後、1%未満のデータが新しいテーブルにコピーされました。

1
おい...それは14億レコードです。百万ではない、十億。それは沢山。とにかく時間がかかるよ。

この方法を選択した場合は、コピーを小さなチャンクに分割してください。各コピーについて約1億から2億と言います。

1
@decompiled、それを小さなチャンクに分割しても何も起こりません(実際には、効率が低下する可能性があります)。@ Bryan、14億件のレコードがあっても、1,000時間はかかりません。

0

これを最善の方法で実行する方法がまだわからない場合は、オンラインのテーブル変更ツールを使用することをお勧めします。

それらの多くはインターネット上にあり、有名なものの1つは次のとおりです。

大きなテーブル(500mil以上のレコード)でも同じ問題があり、変更は完全に行われます。新しいtmpテーブルを作成し、元のテーブルにトリガーを追加し(新しい更新/削除/挿入レコード用)、その間にすべてのレコードを新しいテーブルに(新しい構造で)コピーします

幸運を!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.