web-dev-qa-db-ja.com

mysqlは、数百万のレコードの後、長い時間をかけてインデックス付きテーブルに挿入します

このようなテーブルがあります

CREATE TABLE IF NOT EXISTS `dnddata` (
  `numbers` varchar(10) NOT NULL,
  `opstype` char(1) NOT NULL,
  PRIMARY KEY (`numbers`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
/*!50100 PARTITION BY KEY (numbers)
PARTITIONS 25 */;

3億件のレコードを挿入する必要があります。 csvファイルからload data in fileを使用して毎回1000万レコードを挿入しています。

最初に5分近くかかって1000万件のレコードを挿入する。時間は徐々に増加しています。 3000万件のレコードの後、挿入が停止し、100%サーバーを使用してメモリが応答しなくなります。

my.cnfファイル設定の下

bulk_insert_buffer_size = 100M
key_buffer = 100M
sort_buffer_size = 50M
read_buffer = 50M

2 GメモリのCPUを使用しています。

3000万レコードの詳細

    Space usage
Type    Usage
Data    545.3   MiB
Index   694.8   MiB
Total   1,240.1 MiB

MySQL client version: 5.5.14

インデックスなしでは、50秒で1,000万回挿入されます。

どのような設定を変更する必要があるか教えてください。

ユーザーの回答に基づいて編集

My.cnf設定を以下に変更しました

key_buffer_size = 1G
sort_buffer_size = 4M
read_buffer_size = 1M
read_rnd_buffer_size = 1M
join_buffer_size = 2M
bulk_insert_buffer_size = 32M
myisam_sort_buffer_size = 256M

無駄だ。問題は解決されていません。

以下の方法でデータをロードしました

set autocommit = 0; //for innodb
load data infile into …
COMMIT;

START TRANSACTION; 
load data infile into …
COMMIT;

ALTER TABLE dnddata DISABLE KEYS;
load data infile into …
ALTER TABLE dnddata ENABLE KEYS;

運が悪い.

7
sankar.suda

データの読み込みを高速化するには、このような巨大なファイルをチャンクで読み込む必要があります。ここでは、巨大なLoad local dataファイルの読み込みに関する問題と、それを解決して高速化する方法について説明します。

http://www.mysqlperformanceblog.com/2008/07/03/how-to-load-large-files-safely-into-innodb-with-load-data-infile/

  • MyISAMテーブルでは、データのロードを高速化するために次の手順に従う必要があります。

テーブルに多くのインデックスがある場合、MyISAMテーブルの追加の作業により、LOAD DATA INFILEをさらに高速に実行できます。

  1. FLUSH TABLESステートメントまたはmysqladmin flush-tablesコマンドを実行します。

  2. Myisamchk --keys-used = 0 -rq/path/to/db/tbl_nameを使用して、テーブルのインデックスの使用をすべて削除します。

  3. LOAD DATA INFILEを使用してデータをテーブルに挿入します。これはインデックスを更新しないため、非常に高速です。

  4. myisamchk -rq /path/to/db/tbl_nameを使用してインデックスを再作成します。これにより、ディスクに書き込む前にメモリにインデックスツリーが作成されます。これにより、大量のディスクシークが回避されるため、LOAD DATA INFILE中にインデックスを更新するよりもはるかに高速になります。結果のインデックスツリーも完全にバランスが取れています。

  5. FLUSH TABLESステートメントまたはmysqladmin flush-tablesコマンドを実行します。

LOAD DATA INFILEは、データを挿入するMyISAMテーブルが空の場合、前述の最適化を自動的に実行します。自動最適化とプロシージャを明示的に使用することの主な違いは、サーバーがLOAD DATA INFILEステートメントを実行するときにインデックスの再作成に割り当てるよりも、myisamchkにインデックスの作成用にはるかに多くの一時メモリを割り当てることができることです。

Myisamchkではなく次のステートメントを使用して、MyISAMテーブルの一意でないインデックスを無効または有効にすることもできます。これらのステートメントを使用する場合、FLUSH TABLE操作をスキップできます。

ALTER TABLE tbl_name DISABLE KEYS;
ALTER TABLE tbl_name ENABLE KEYS;

詳細については、以下を参照してください。

http://dev.mysql.com/doc/refman/5.5/en/optimizing-myisam-bulk-data-loading.html

https://wiki.rice.edu/confluence/display/~as43/Make+LOAD+DATA+INFILE+run+even+faster+for+a+MyISAM+table

6
Mahesh Patil

CREATE TABLEコマンドにインデックスがありませんでした(主キー以外)。問題から除外しただけで実際に存在する場合は、LOAD DATAコマンドの前にインデックスを無効にして、完了後に再構築できます。

ALTER TABLE dnddata DISABLE KEYS;

LOAD DATA INFILE ... ;

ALTER TABLE dnddata ENABLE KEYS;

テーブルが大きくなると、インデックスを書き込む時間が長くなります。

2
Derek Downey

MyISAMテーブルを扱っているので

CREATE TABLE dndtemp ENGINE=MyISAM SELECT * FROM dnddata WHERE 1=2;
LOAD DATA INFILE ... INTO TABLE dndtemp ... ;
INSERT INTO dnddata SELECT * FROM dndtemp;
DROP TABLE dndtemp;

一時テーブルにはインデックスがないため、LOAD DATA INFILEの方が高速です。

DISABLE KEYS/ENABLE KEYSは、セカンダリインデックスがないため、このインスタンスでは役に立ちません。

MyISAMインデックスの合計は694.8 MiBであり、MyISAMはインデックスページのみをキャッシュするため、キーバッファーは今の​​ところ768Mにサイズ変更できます。

試してみる !!!

UPDATE 2012-07-25 10:06 EDT

MyISAMテーブルの一括読み込みに対応するため、 bulk_insert_buffer_size を512Mに増やす必要があります。 bulk_insert_buffer_sizeのMySQLドキュメントによると:

MyISAMは特別なツリーのようなキャッシュを使用して、空でないデータをデータに追加するときに、INSERT ... SELECT、INSERT ... VALUES(...)、(...)、...、およびLOAD DATA INFILEの一括挿入を高速化します。テーブル。この変数は、スレッドあたりのバイト数でキャッシュツリーのサイズを制限します。 0に設定すると、この最適化が無効になります。デフォルト値は8MBです。

これと、2 GBのRAM=(DBが今でも存続する方法は?)

[mysqld]
bulk_insert_buffer_size=512M
key_buffer_size=512M
1
RolandoMySQLDBA

IMHO、2GBのRAMは、MySQLが3000万行を効率的に処理するには不十分です。

それでも、key_bufferが小さすぎます。このボックスが専用のデータベースボックスで、2G RAMしかない場合は、安全に最大1Gにして、ディスクに頻繁にスワップしないでください。

key_buffer = 1GB 
1
randomx