2016-09-14 56 views
2

ありがとうございます。私のデータベースをMySQL 5.5から5.7にアップグレードする際に問題が発生しました。私は完全に完全に混乱しています。アップグレードはmysqldumpなどを使用して行われていませんでしたが、複数の非常に長いSQLスクリプトを使用して複数のタブで区切られた入力ファイルから再構築しました。 (ストアドプロシージャ内の)具体的には一つの一見無害なクエリは私に迷惑を与えてきたと私はなぜうまくいかないことができます。SELECTサブクエリを使用するUPDATEは、MySQL 5.7では非常に遅く実行されますが(5.5でも問題ありませんでした)

UPDATE liverpool.master_person mp 
SET Link_Count = (SELECT count(*) FROM liverpool.person_record pr 
WHERE mp.Master_Person_ID = pr.Master_Person_ID) - 1; 

これはかなり単純なようだが、このクエリからEXPLAINは、いくつかの深刻な行走査が起こっていることを示してい上:

# id | select_type   | table | partitions | type | possible_keys | key     | key_len | ref | rows  | filtered | Extra 
======================================================================================================================================================================== 
'1' | 'UPDATE'    | 'mp' | NULL  | 'index' | NULL   | 'PRIMARY'    | '4'  | NULL | '1198100' | '100.00' | NULL 
------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 
'2' | 'DEPENDENT SUBQUERY' | 'pr' | NULL  | 'index' | NULL   | 'Master_Person_ID_IDX' | '17' | NULL | '1200537' | '100.00' | 'Using where; Using index' 

重要なことは、UPDATEのための1198100およびSELECTサブクエリのための1200537である行列、のようです。これらの数値は、両方とも参照先テーブルの両方の合計行数にかなり近くなっています(両方とも1207744)。だから両方の行をスキャンするために完全な行をしているように見えますが、なぜそれは見えません。正確に同じクエリがMySQL 5.5で正常に機能しました。 this解決策が助けになると思っていましたが、 'derived_merge = off'をoptimizer_switchに渡してサーバーを再起動しても役に立たなかったことを期待していました。

私は確かにこのクエリが超高速であるとは思わない。必ずしもそうである必要はありません。以前はスピードが速かったのですが(7200rpm回転ディスクでは数分)、MySQL 5.7へのアップグレード以来、これは宇宙の猛暑の前にいつでも完了しないようです。長いです。誰もそこに誰かがアイデアを持っていますか?クエリの書き換え、my.iniの設定など

また、私が何らかの方法でプロトコルを破っているのか、私が質問を改善できるかどうか、私に知らせてください。私が上で言ったように、それは私の最初の投稿です。

ありがとうございます。

EDIT:this解決策が有望であると私は考えました。明らかに異なる文字セット/照合を持つテーブルは、お互いのインデックスを正しく読み取ることができません。私はかなりすべてがlatin1にあったことを確信していたが、確かめる価値があると考えた。だから私はCREATE TABLEステートメントのすべてに明示的にDEFAULT CHARSET=latin1を追加し、CHARACTER SET latin1LOAD DATA INFILEステートメントに追加しました。悲しいことに、変化はありません。

+0

は私が適切にフォーマットされたEXPLAIN親切な人にありがとう! – convensive

+1

Q:\ '' Master_Person_ID' \ '\' 'Master_Person_ID_IDX' \'インデックスの先頭の列ですか?サブクエリがある場合は、サブクエリがかなり速くなると期待しています。このサブクエリは、100万回(外部クエリの各行に対して1回)実行する場合、高速にする必要があります。InnoDBのバッファプールサイズ(これがInnoDBテーブルの場合)が考慮されます。このステートメントを "ステートメント"ベースでログ記録するのか、それともバイナリーログであるのか。また、ロールバックの生成、行ロック取得(他のDML文によるロックによる競合)などもあります。 – spencer7593

+0

@ spencer7593 'liverpool.person_record'テーブルの' Master_Person_ID_IDX'は、 'CREATE INDEX Master_Person_ID_IDX ON liverpool .person_record(Master_Person_ID ASC); '' Master_Person_ID'は、(私が正しくあなたを理解している場合)先行する唯一の列です。 – convensive

答えて

0

は、としてクエリを書き直すようにしてください:

UPDATE liverpool.master_person mp 
    JOIN (SELECT Master_Person_ID, count(*) as cnt 
      FROM liverpool.person_record 
     GROUP BY Master_Person_ID) 
     ) pr 
    ON mp.Master_Person_ID = pr.Master_Person_ID 
    SET mp.Link_Count = pr.cnt - 1 
+0

こんにちはMike。これは魅力のように機能します!どうもありがとうございました!あなたがニュージーランドのウェリントンにいるなら、私はあなたにビールを買うでしょう。クエリは約101秒で実行されます。これは、必要な処理が十分に高速です。しかし、私はこの構文が不思議です。それはバックグラウンドで何をしていますか?オプティマイザが一時的にSELECTをテンポラリ・テーブルに具体化していますか? – convensive

+0

これを答えとしてマークします。しかし、もし私が上記のような一見単​​純明快なクエリがMySQL 5.7で非常に遅くなければならない理由について誰かが洞察しているなら、私はそれについて聞くのが大好きです。 – convensive

+0

@convensiveリクエストは1行 "A"で、それぞれのリクエストは "B"で表示されます。さらに、フルテーブルスキャンを使用して、明らかにインデックスが遅いと信じています。 私のクエリは、テーブルの1回のパスですべての金額を収集します(インデックス上だけでも可能です)。次に更新に進みます。彼は一時的なテーブルやストアをメモリに集めていますか?結果レコードの数に依存します – Mike

関連する問題