2016-06-25 11 views
1

私は、あるマシンでホストされているMySQLデータベースと、ローカルネットワーク上で読み書きする他のマシンで実行されている6クライアントを使用するアプリケーションを持っています。MySQLのアップデートが徐々に遅くなります

私は、作業する行に約120,000の項目を含む1つのメイン作業表を持っています。各クライアントは、割り当てられていない40個の作業項目をテーブルから取得し(割り当て済みとしてマークする)、作業を行い、結果を同じ作業表に書き戻します。この作業は、これ以上行うことができなくなるまで続きます。

enter image description here

上記更新クエリを使用して、クライアントのいずれかから表40の結果の各ブロックをライトバックにかかる時間の量を示す写真です。ほとんどの時間は持続時間がかなり短いことがわかりますが、突然持続時間は300秒になり、すべての作業が完了するまでそこにとどまります。最後までクエリを実行する時間のこの急激な増加は、私が助けが必要なものです。

クライアントに負荷がかかりません。サーバーは少ししか搭載されていますが、16GBのRAMと8つのコアがあり、このdbのホスティング以外は何もしていません。

ここに関連するSQLコードがあります。

表の作成:

CREATE TABLE work (
    item_id MEDIUMINT, 
    item VARCHAR(255) CHARACTER SET utf8, 
    allocated_node VARCHAR(50), 
    allocated_time DATETIME, 
    result TEXT); 
/* Then insert 120,000 items, which is quite fast. No problem at this point. */ 
INSERT INTO work VALUES (%s,%s,%s,NULL,NULL,NULL); 

クライアント上で動作するように40の項目を割り当てる:

UPDATE work SET allocated_node = %s, allocated_time=NOW() 
     WHERE allocated_node IS NULL LIMIT 40; 
SELECT item FROM work WHERE allocated_node = %s AND result IS NULL; 

アップデート完了結果に行(これは数時間後には本当に遅くなる部分です実行中):

/* The chart above shows the time to execute 40 of these for each write back of results */ 
UPDATE work SET result = %s WHERE item = %s; 

私はUbuntu 14.04ですべての標準設定ings。 最終テーブルは約160MBで、インデックスはありません。

私の質問に間違いはありませんし、全体的に2倍の時間がかかります。

これらの問題の経験をお持ちの方は、このパフォーマンスの問題を解決するためにMySQLで変更する必要がある設定を示唆することができますか、またはチャートのタイミングを説明する可能性のある問題を指摘してください。

ありがとうございました。

+0

「仕事」はどれくらい大きくなるのですか? 'innodb_buffer_pool_size'と' key_buffer_size'の値は何ですか?どのエンジンが使用されていますか? –

答えて

0

インデックスがないと、完全なテーブルがスキャンされます。アイテムIDが大きくなると、更新する行を取得するためにテーブルの量を増やす必要があります。 私は、おそらくindexをitem_idの主キーにしようとしますか?

このようなマシンでは、継続時間の増加が大きすぎると思われます。

+0

あなたの答えをありがとう。インデックスが更新する行を見つけるのが速くなることは理解していますが、それが問題であれば、時間の直線的な増加は期待できません。このグラフは、更新の期間が大幅に延長された後のしきい値を示しています。 – user1592096

+0

あなたとイゼルニの答えは正しいです。 'item'にインデックスを追加すると、パフォーマンスの問題が解決されました。ありがとうございました。 – user1592096

0

適切な診断(詳細は後述)が必要な場合は、2つの潜在的なパフォーマンス低下の可能性があります。

一つは、あなたが

CREATE INDEX table_ndx ON table(allocated_node, item); 

を改善することができますが、それはそうカーディナリティの低いそうに見えるSchlemiel画家の問題に実行しているということです。MySQLは、割り当てられていないノードを探すのにあまり時間がかかりません。

もっと可能性の高い説明は、クライアント間で何らかの種類のロック競合が発生している可能性があります。確かに、システムが停止されているものを300秒の間には、MySQLへの管理者接続から

SHOW FULL PROCESSLIST 

を実行します。それが何を言いたいのかを見て、あなたの質問を更新するためにそれを使うかもしれません。また、

SHOW CREATE TABLE 

の結果を使用しているテーブルに対して投稿してください。

あなたはこのような何かをやっている必要があります。

START TRANSACTION; 
allocate up to 40 nodes using SELECT...FOR UPDATE; 
COMMIT WORK; 
-- The two transactions serve to ensure that the node selection can 
-- never lock more than those 40 nodes. I'm not too sure of that LIMIT 
-- being used in the UPDATE. 

START TRANSACTION; 
select those 40 nodes with SELECT...FOR UPDATE; 
<long work involving those 40 nodes and nothing else> 
COMMIT WORK; 

あなたは、単一のトランザクションとテーブルレベルのロック(でも、暗黙的に)を使用する場合、1つのクライアントは、他のすべてをロックアウトしていることが起こるかもしれません。理論的には、これはMyISAMテーブル(テーブルレベルのロックしかない)でのみ起こるはずですが、InnoDBテーブルでもスレッドが古くなっているのを見てきました。

+0

私は現在明示的なロックを使用していませんが、それでも暗黙的にロックが起こっていると言っていると思いますか?また、トランザクションの使用に慣れていません。トランザクション2は、トランザクションが完了するまでテーブルをアクセスからロックしますか?他のクライアントはブロックされますか? – user1592096

+0

理論上、SELECTはブロックしてはならず、InnoDBテーブルのUPDATEは影響を受ける行だけをロックします。実際には、SELECTとサブクエリを含む複雑なUPDATEを見てきました*関連するすべてのテーブル*をロックしています*私はたぶんクエリを単純化するために一時テーブルとMEMORYテーブルを使い過ぎる傾向があります。しかし、何が起こっているのかを本当に確かめるためには、プロセスリストやエンジンステータスをチェックする必要があります。 – LSerni

+0

ありがとうございます。 「エンジンの状態」を確認するための推奨事項は何ですか? – user1592096

0

あなたの「外部ロック」技術はうまく聞こえます。

INDEX(allocated_node)は、最初のUPDATEで大きく役立ちます。

INDEX(item)は、最終的には役立ちますUPDATE

(2列を持つ複合インデックスの両方が、アップデートを1つだけではないのに役立ちます。)

突然の増加の理由:あなたは継続的にテーブルのサイズが成長すること、大きなTEXTフィールドに入力されています。ある時点では、テーブルは非常に大きく、RAMにキャッシュすることはできません。したがって、キャッシュされてからフル・テーブル・スキャンになります。

...; SELECT ... FOR UPDATE; COMMIT;FOR UPDATEはすぐにCOMMITが発生するため役に立たない。

あなたは「40」で遊ぶことができますが、なぜ大小の数字が役立つのだろうとは思いません。

関連する問題