2012-02-02 10 views
9

私は最近、私のプロジェクトテーブルをInnoDBに切り替えました(関係が良いことだと思っています)。私は一度に約500の製品を索引付けするためにPHPスクリプトを使用しています。InnoDBが非常に遅く挿入されて遅くなります

ワード/ IDSの関連付けを格納するテーブルは:

CREATE TABLE `windex` (
`word` varchar(64) NOT NULL, 
`wid` int(10) unsigned NOT NULL AUTO_INCREMENT, 
`count` int(11) unsigned NOT NULL DEFAULT '1', 
PRIMARY KEY (`wid`), 
UNIQUE KEY `word` (`word`) 
) ENGINE=InnoDB AUTO_INCREMENT=324551 DEFAULT CHARSET=latin1 

別のテーブルにプロダクトID /単語IDの関連付け:

CREATE TABLE `indx_0` (
`wid` int(7) unsigned NOT NULL, 
`pid` int(7) unsigned NOT NULL, 
UNIQUE KEY `wid` (`wid`,`pid`), 
KEY `pid` (`pid`), 
CONSTRAINT `indx_0_ibfk_1` FOREIGN KEY (`wid`) REFERENCES `windex` (`wid`) ON DELETE CASCADE ON UPDATE CASCADE, 
CONSTRAINT `indx_0_ibfk_2` FOREIGN KEY (`pid`) REFERENCES `product` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 

スクリプトはMyISAMテーブルとインデックスの製品を使用して試験した比較的速い(くらいですInnoDBよりはるかに高速です)。初めてInnoDBを走らせるのは馬鹿げて遅かったですが、より多くの値を入れ子にした後、私はそれを十分にスピードアップしました。

私はinnodbがこのタイプのもののほうがローレベルのロックのためにはるかに高速だと思いますが、そうではありません。

SELECT 
title,keywords,upc,... 
FROM product 
WHERE indexed = 0 
LIMIT 500 

は私がループを作成してにwindexに追加され、必要なすべての単語ID /プロダクトIDのペアする必要があるすべての単語で配列を埋める:

私はのようになりますクエリを作成しますindx_0に追加されます。

innodbは値が重複しているために失敗した "REPLACE INTO"または "INSERT IGNORE INTO"を実行するたびに自己インクリメント値を増やし続けるため、追加する値が存在していないことを確認する必要があります。私は最初、このような似たクエリを使用して、存在するすべての値を選択することを行うには:

SELECT wid,word 
FROM windex 
WHERE 
word = "someword1" or word = "someword2" or word = "someword3" ... ... 

をそれから私は私が追加するすべての新しい単語が100%新しいですので、存在して結果に対する私の配列をフィルタリングします。

これは全体の実行時間の約20%を要します。他の80%は、より多くの値があるindx_0にペア値を追加することになります。

ここに私が得るものの例があります。

0.4806秒。 (合計0.4807秒)。
0.0319秒で500個のアイテムを収集します。 (合計0.5126秒)。
比較のためにwindex値を選択するのに5.2396秒。 (合計5.7836秒)。
カウントを更新するのに1.8986秒。 (合計7.6822秒)。
8秒間のwindexレコードを追加するのに0.0641秒。 (合計7.7464秒)。
17.2725秒に3435個のpid/widペアのインデックスを追加します。 (合計25.7752秒)。
操作は、500製品を索引付けするのに26.07秒かかりました。

3435ペアは、すべてのような単一のクエリで実行されている:

INSERT INTO indx_0(pid,wid) 
VALUES (1,4),(3,9),(9,2)... ... ... 

なぜInnoDBが私の場合はMyISAMテーブルよりもそんなに遅いですか?

+0

検索機能を作成するには、単語インデックスという考えですか?その場合、solrやmysql全文検索のような実際の検索エンジンを調べてください。そのような特定のタスクを上回ることはできません。 –

答えて

13

InnoDBはMyIsam(FOREIGN KEYS)よりも複雑なキー構造を提供し、再生成キーはInnoDBでは実際には遅いです。すべてのupdate/insert文を1つのトランザクションに入れてください(実際にInnoDBではかなり高速ですが、InnoDbテーブルに2つのインデックスを挿入するクエリが約300,000件あり、10,000個の挿入をBEGIN TRANSACTIONに入れたら約30分かかります) COMMITは2分未満で完了しました)。

私が使用することをお勧めします:

BEGIN TRANSACTION; 
SELECT ... FROM products; 
UPDATE ...; 
INSERT INTO ...; 
INSERT INTO ...; 
INSERT INTO ...; 
COMMIT; 

これは、InnoDBは一度だけ百いない数回のインデックスを更新するようになります。それは私が同様の問題を持っていたし、デフォルトのinnodb_flush_log_at_trx_commitがHDDのログファイルのすべての挿入/更新クエリをフラッシュしている有効でInnoDBが持っているようだ

+0

確かに私は信じるために改善が必要です。私はVyktorと同様の問題があります。これはうまくいくようです。ありがとう-Uday – Uday

+2

私はこの問題を(90秒から0.9まで)固定しているという問題を抱えていました。InnoDBに必要なことをゆっくりと学んでいます –

+0

@Vyktorについて、 "私は10,000回の挿入をBEGIN TRANSACTION' 'COMMIT'は2分もかからなかった" *、なぜ10kバッチに分割するのですか? **すべての**声明を1回の取引で囲んでみませんか? – Pacerier

4

を働いていた場合

は私を知ってみましょう。ハードディスクの書き込み速度はこのプロセスのボトルネックです。

ので、再起動のMySQLサービス

`innodb_flush_log_at_trx_commit = 0` 

MySQLの設定ファイルを変更してみてください。

私は挿入時に約100倍のスピードアップを経験しました。

+1

このオプションを適用すると、トランザクションの安全性が失われることに注意してください...クライアントに指示した後に電源が切れた場合、実際にディスクに書き込まれる前に永久に失われることになります。 – Cine

関連する問題