2017-11-22 10 views
1

複数の列を使用して、テーブルAからテーブルBへの記録を照合するための並べ替えを行うことを試みています。しかし何らかの理由でクエリが非常に遅いです。私は、結合されたテーブルの異なるインデックスの組み合わせを実験しようとしましたが、それらは使用されていません。そのため、常にフルテーブルスキャンを行っています。複数のJOIN varchar条件を持つテーブルのインデックス

SELECT 
    nc.id, nc.firstName, nc.lastName, 
    nc.firmName, nc.location, 
    nc.city AS city, nc.state AS state, 
    ac.id, ac.lastName, ac.firstName, ac.middleName, 
    IFNULL(ac.suffixName, '') AS suffixName, ac.firmName, ac.city, ac.state 
FROM 
    NormalContacts AS nc 
JOIN 
    AllContacts AS ac ON ((nc.firstName = ac.firstName AND nc.lastName = fa.lastName) OR (nc.firstName = fa.middleName AND nc.lastName = ac.lastName)) 
     AND (ac.city = nc.city AND ac.state = nc.state) 
JOIN 
    FirmInputTable AS fit ON (fit.firmName = fa.firmName AND fit.otherFirmName = nc.firmName)  
WHERE 
    nc.crdNumber IS NULL AND nc.city IS NOT NULL AND nc.state IS NOT NULL AND nc.firmName IS NOT NULL 

NormalContactsAllContactsは337250のレコードですしながら、1,000レコードです。 JOIN条件のすべてのフィールドはvarcharです。ここで

EXPLAIN結果である:

enter image description here

*スクリーンショットAllContactsでFA、タイプミスのため申し訳ありません。

誰でもこのクエリを最適化する方法を提案したり、間違っていることを教えてください。前もって感謝します!

+1

私たちにはじめてご相談ください - http://sqlfiddle.com/あなたはより高い品質の応答を得る可能性が高いです。特に、あなたのインデックスを見せてください。 –

+0

J_Hの提案通り、フィドルを使うことができます。オプティマイザがあなたが提案したインデックスを強制的に使用させるために 'use index'を使ってみましたか? –

答えて

1

オプティマイザは、インデックスと統計情報を調べて、テーブルの実行順序を決定します。

以下では、ONはテーブルどうしの関係のみを示し、WHEREはフィルタリングのみを対象としています。

「最初の」テーブルは、最も選択的な条件がWHEREのものです(必ずしもそうである必要はありません)。したがって、INDEXWHEREの列に注目する必要があります。 (場合によってはGROUP BYまたはORDER BYが出現する)

JOINシーケンスの他のテーブルには、 "Nested Loop Join"を介して到達します。これは、 "前のテーブルの各行について、現在のテーブルの行をフェッチする"のところです。このフェッチを実行するには、テーブルに関連するWHERE句と、このテーブル(おそらくこれまでのテーブル)に言及しているONのものを使用します。だから、WHEREONの条件からこのテーブルのINDEXを考えてみてください。

オプティマイザがどのような順序でテーブルを参照するかは必ずしも予測できないため、可能な各順序に対応するためにインデックスを追加することをお勧めします。

典型的なショートカットは、WHEREには1つのテーブルのみが記載されています。そのテーブルは最初に選ばれることがほぼ確実です。

WHERE/ONのものがあれば、特定のテーブルの良いインデックスを構築するにはどうすればよいですか?グッド - あなたは適切ONsWHEREsを分割しているように見える

...あなたのケースについてmy cookbook

を参照してください。

ncWHEREに記載されている唯一のテーブルのようです。したがって、オプティマイザが起動すると思われます。

IS NULLは、= constantと似ていますが、IS NOT NULLは、最適化しやすい範囲ではありません。私は

nc: INDEX(crdNumber, state) 

(ここでは、私は nc列が NULLであることが最も/少なくともそうな時に推測しています。)をお勧めします

nc後、唯一のacは(別名faは???)来ることができ:

ON ((...) OR (...)) 
    AND ac.city = nc... 
    AND ac.state = nc... 

ORは、インデックスまたは最適化することは通常不可能であるので、我々は

に残っています

ON fit.firmName = ... 
    AND fit.otherFirmName = ... 

fit: INDEX(firmName, otherFirmName) -- in either order 
につながる:0
ac: INDEX(city, state) -- in either order 

おそらくlastName最後に、fitそれによって

ac: INDEX(city, state, firstName) -- in any order 

につながる、ORの(AC/FAを固定した後に)引き抜くことができ

はクエリにfaを修正しました。必要に応じて私の答えを修正します。

注:INDEX(a,b)は、がより好ましく、INDEX(a), INDEX(b)より良い場合があります。

+0

驚くばかり! 1〜2分で実行されていたクエリは、1〜3秒かかるだけです。私はそれが 'first'、' lastName'、および 'middleName'の索引を作成しようとしていたが、失敗したので、遅くする' OR'条件だと思って失敗しました。私は、「都市」と「州」の索引を追加する必要はなく、必要なだけです。お勧めのインデックスをありがとう! :D – mcspiral

関連する問題