2012-02-16 7 views
0

私はいくつかのコードを継承していますが、元の著者は連絡がつかないので、私自身のMySQLの知識があまり良くないので、援助に非常に感謝します。MySQLのクエリ

私は実行するのに約4秒かかっており、すべてのテーブルに約20,000行のデータしかありませんので、おそらく複数のテーブルに分割することでより効率的にクエリを実行できますクエリは、ここにあります:

SELECT SQL_CALC_FOUND_ROWS ci.id AS id, ci.customer AS customer, ci.installer AS installer, ci.install_date AS install_date, ci.registration AS registration, ci.wf_obj AS wf_obj, ci.link_serial AS link_serial, ci.sim_serial AS sim_serial, sc.call_status AS call_status 
    FROM ap_servicedesk.corporate_installs AS ci 
    LEFT JOIN service_calls AS sc ON ci.wf_obj = sc.wf_obj 
    WHERE ci.acc_id = 3 
    GROUP BY ci.id 
    ORDER BY link_serial 
       asc 
    LIMIT 40, 20 

これをより効率的にする方法はありません。

(いくつかの値が変数として設定するが、PHPMyAdminの上記のクエリを実行しているかかり〜4secs)

id列が主インデックスです。要求されたよう

詳細:

corporate_installsテーブル:

service_callsテーブル

Field  Type Null Key Default Extra 

id    int(11) NO PRI NULL auto_increment 
customer  varchar(800) NO  NULL  
acc_id  varchar(11) NO  NULL  
installer  varchar(50) NO  NULL  
install_date varchar(50) NO  NULL  
address_name varchar(30) NO  NULL  
address_street varchar(40) NO  NULL  
address_city varchar(30) NO  NULL  
address_region varchar(30) NO  NULL  
address_post_code varchar(10) NO  NULL  
latitude   varchar(15) NO  NULL  
longitude   varchar(15) NO  NULL  
registration varchar(50) NO  NULL  
driver_name   varchar(50) NO  NULL  
vehicle_type varchar(50) NO  NULL  
make   varchar(50) NO  NULL  
model   varchar(50) NO  NULL  
vin     varchar(50) NO  NULL  
wf_obj   varchar(50) NO  NULL  
link_serial   varchar(50) NO  NULL  
sim_serial   varchar(50) NO  NULL  
tti_inv_no   varchar(50) NO  NULL  
pro_serial   varchar(50) NO  NULL  
eco_serial   varchar(50) NO  NULL  
eco_bluetooth varchar(50) NO  NULL  
warranty_expiry varchar(50) NO  NULL  
project_no   varchar(50) NO  NULL  
status   varchar(15) NO  NULL  

Field   Type   Null Key Default Extra 
id     int(11)  NO  PRI NULL auto_increment 
acc_id   int(15)   NO  NULL  
ciid   int(11)   NO  NULL  
installer_job_no varchar(50) NO  NULL  
installer_inv_no varchar(50) NO  NULL  
engineer   varchar(50) NO  NULL  
request_date varchar(50) NO  NULL  
completion_date varchar(50) NO  NULL  
call_status   varchar(50) NO  NULL  
registration varchar(50) NO  NULL  
wf_obj   varchar(50) NO  NULL  
driver_name   varchar(50) NO  NULL  
driver_phone varchar(50) NO  NULL  
team_leader_name varchar(50) NO  NULL  
team_leader_phone varchar(50) NO  NULL  
servicing_address varchar(150) NO  NULL  
region   varchar(50) NO  NULL  
post_code   varchar(50) NO  NULL  
latitude   varchar(50) NO  NULL  
longitude   varchar(50) NO  NULL  
incident_no   varchar(50) NO  NULL  
service_type varchar(20) NO  NULL  
fault_description varchar(50) NO  NULL  
requested_action varchar(50) NO  NULL  
requested_replacemt varchar(100) NO  NULL  
fault_detected varchar(50) NO  NULL  
action_taken varchar(50) NO  NULL  
parts_used   varchar(50) NO  NULL  
new_link_serial varchar(50) NO  NULL  
new_sim_serial varchar(50) NO  NULL  

(書式設定のための謝罪が、私は最善を尽くした私ができる)

あなたにもっと感謝が必要な場合はお知らせください。

さらに情報(私はEXPLAINでクエリをもう一度やった):

id select_type table type possible_keys key key_len ref rows Extra 
1 SIMPLE ci ALL acc_id NULL NULL NULL 7227 Using where; Using temporary; Using filesort 
1 SIMPLE sc ALL NULL NULL NULL NULL 410 
+0

クエリではなく問題がある可能性があるため、テーブル構造を提供することもできます – Ryan

+0

[コードレビュー](http://codereview.stackexchange.com/?as=1)または[データベース管理者](http://dba.stackexchange.com/?as=1) –

答えて

2

2つのwf_obj列のインデックスを追加すると、link_serial列(acc_idのインデックスも必要な場合があります)。

SELECT ... 
FROM 
     (SELECT * 
     FROM ap_servicedesk.corporate_installs 
     WHERE acc_id = 3 
     ORDER BY link_serial ASC 
     LIMIT 60 
    ) AS ci 
    LEFT JOIN service_calls AS sc 
    ON sc.PK =       --- the PRIMARY KEY of the table 
    (SELECT PK 
     FROM service_calls AS scm 
     WHERE ci.wf_obj = scm.wf_obj 
     ORDER BY scm. --- whatever suits you 
     LIMIT 1 
    ) 
ORDER BY ci.link_serial ASC 
LIMIT 20 OFFSET 40 

ORDER BY scm.SomeColumnはないパフォーマンスのために必要とされているが、一貫性のある結果を得るために:

は、このバージョンを試してみてください。そのままのクエリは、最初のテーブルから2番目のテーブルのすべての関連する行に行を結合しています。しかし、最後のGROUP BYは(2番目のテーブルの)これらすべての行を集約するので、SELECT ... sc.call_statusは、これらの行のいずれかから多かれ少なかれランダムcall_statusを選択します。

+0

ありがとう、私はエラーが表示されます:#1064 - SQL構文にエラーがあります。あなたのMySQLサーバーのバージョンに対応するマニュアルをチェックしてください。正しい構文は、 'SELECT PK FROM service_calls AS scm WHERE ci.wf_obj = scm.wf_obj'の行11にあります。 – davidjwest

+0

'PK'を書いてはいけません。プライマリキー列を代わりに入力してください。 –

+0

多くのおかげで、はるかに速くなったようですが、正しく動作させるようにして、報告します。 – davidjwest

2

私はこの上で見てね最初の場所は、インデックスでなければならないであろう。

ci.idにはグループ化されたPKがありますが、link_ser(ソーステーブルは未定義)で注文していますが、ci.acc_idに基づいて選択しています。

フィールドacc_idのテーブルcorp_installsに余分なキーを追加すると、WHERE句に使用できるようになり、パフォーマンスだけが向上します。

さらに、あなたはci.wf_obj = sc.wf_objを結合内に持っています。 VARCHARに参加するSLOWこと、そしてあなたは、選択基準の一部としてこれを使用して、実際にはありませんので、サブクエリはこれに加えて、以下の

SELECT 
    serviceCallData.*, 
    sc.call_status AS call_status 

FROM (
    SELECT 
    SQL_CALC_FOUND_ROWS AS found_rows, 
    ci.id AS id, 
    ci.customer AS customer, 
    ci.installer AS installer, 
    ci.install_date AS install_date, 
    ci.registration AS registration, 
    ci.wf_obj AS wf_obj, 
    ci.link_serial AS link_serial, 
    ci.sim_serial AS sim_serial 

    FROM ap_servicedesk.corporate_installs AS ci 
    WHERE ci.acc_id = 3 
    GROUP BY ci.id 
    ORDER BY ci.link_serial ASC 
    LIMIT 40, 20 
) AS serviceCallData 
LEFT JOIN serice_calls AS sc ON serviceCallData.wf_obj = sc.wf_obj 

を検討し、あなたの友人であってもよいし、(acc_id)それを変更しますキーを(acc_id、link_serial)にすると、ソートで使用できるようになります。また、(wf_obj)のキーをserice_callsに追加します。

これは私が私が使用SQL_CALC_FOUND_ROWSオプションを考えて、これは助け

+0

おかげさまで、今は2分の1秒ほど早くなりましたが、少しは改善が望めました。それ以上のアドバイスをいただければ幸いです。 – davidjwest

+0

あなたのスキーマを見れば、最大の警鐘はci.wf_obj = sc.wf_objのLEFT JOINです。どちらもVARCHAR(50)です。これは特に大規模なデータセットでは遅くなります。 wf_objのキーをservice_callsテーブルに追加し、その前のキーをacc_id、wf_objに変更することもできますが、これはおそらく大きな改善をもたらさないでしょう。まもなく回答が更新されます –

1

であると思いcorpoprate_installsテーブルから20行を選択し、唯一の非効率的なVARCHARが

に参加使っservice_callsテーブル上にそれらを結合します(パフォーマンスが低下する可能性があります(いくつかのテストではhere、情報はSQL_CALC_FOUND_ROWS here)。その場合、インデックスは使用されていないようです。

LIMITの後にCOUNT()が付いた2つのクエリでクエリを置き換えてみてください。

+0

私はこの記事を投稿する前にこの記事を読んでいますが、データの量は私が質問を分割することは多分うまくいくとは思っていませんが、より多くのデータを取得します。アドバイスを感謝します。 – davidjwest