2017-09-22 3 views
2

私はクエリを実行しており、MySQLがそれほどゆっくりと実行している理由を理解するのに苦労しています。以下の3つのシナリオで、実際のクエリとEXPLAINを含めました。遅いMySQLクエリ - 最適化する方法?

最初のクエリは非常に実行が遅く(23秒)、where句から1つのフィールド(クエリ2)を削除すると、クエリは0.010秒で実行されます。これはTinyIntフィールドです(基本的にブール値0/1が格納されます)。

プロジェクト - > hasManyの - >マイルストーン - > hasManyの - >タスク

task_wishlistクエリ1 EXPLAIN QUERY 1

SELECT `tasks`.*, 
     task_wishlist.description AS item_description, 
     task_wishlist.created_at AS item_created_at 
FROM `tasks` 
LEFT JOIN `task_wishlist` ON `tasks`.`id` = `task_wishlist`.`task_id` 
LEFT JOIN `milestones` ON `tasks`.`milestone_id` = `milestones`.`id` 
LEFT JOIN `projects` ON `milestones`.`project_id` = `projects`.`id` 
WHERE `task_wishlist`.`wishlist_id` = '527021' 
    AND `tasks`.`active` = '1' 
    AND `projects`.`active` = '1' 
    AND `milestones`.`active` = '1' 
ORDER BY `task_wishlist`.`created_at` DESC 
LIMIT 25; 
/* Affected rows: 0 Found rows: 25 Warnings: 0 Duration for 1 query: 23.072 sec. (+ 0.040 sec. network) */ 

タスクとウィッシュリストの間のピボットテーブルです。

*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: projects 
    partitions: NULL 
     type: ALL 
possible_keys: PRIMARY 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 997 
    filtered: 10.00 
     Extra: Using where; Using temporary; Using filesort 
*************************** 2. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: milestones 
    partitions: NULL 
     type: ref 
possible_keys: PRIMARY,milestones_project_id_foreign 
      key: milestones_project_id_foreign 
     key_len: 4 
      ref: fusion.projects.id 
     rows: 3 
    filtered: 10.00 
     Extra: Using index condition; Using where 
*************************** 3. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: tasks 
    partitions: NULL 
     type: ref 
possible_keys: PRIMARY,tasks_milestone_id_foreign 
      key: tasks_milestone_id_foreign 
     key_len: 5 
      ref: fusion.milestones.id 
     rows: 5 
    filtered: 10.00 
     Extra: Using where 
*************************** 4. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: task_wishlist 
    partitions: NULL 
     type: ref 
possible_keys: task_wishlist_wishlist_id_foreign,task_wishlist_task_id_foreign 
      key: task_wishlist_task_id_foreign 
     key_len: 4 
      ref: fusion.tasks.id 
     rows: 100 
    filtered: 0.28 
     Extra: Using where 
4 rows in set, 1 warning (0.01 sec) 

クエリ2(milestones.active除去)

SELECT `tasks`.*, 
     task_wishlist.description AS item_description, 
     task_wishlist.created_at AS item_created_at 
FROM `tasks` 
LEFT JOIN `task_wishlist` ON `tasks`.`id` = `task_wishlist`.`task_id` 
LEFT JOIN `milestones` ON `tasks`.`milestone_id` = `milestones`.`id` 
LEFT JOIN `projects` ON `milestones`.`project_id` = `projects`.`id` 
WHERE `task_wishlist`.`wishlist_id` = '527021' 
    AND `tasks`.`active` = '1' 
    AND `projects`.`active` = '1' 
    /*AND `milestones`.`active` = '1'*/ 
ORDER BY `task_wishlist`.`created_at` DESC 
LIMIT 25; 
/* Affected rows: 0 Found rows: 25 Warnings: 0 Duration for 1 query: 0.028 sec. (+ 0.010 sec. network) */ 

クエリ2説明:

*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: task_wishlist 
    partitions: NULL 
     type: ref 
possible_keys: task_wishlist_wishlist_id_foreign,task_wishlist_task_id_foreign 
      key: task_wishlist_wishlist_id_foreign 
     key_len: 4 
      ref: const 
     rows: 7224 
    filtered: 100.00 
     Extra: Using index condition; Using where; Using filesort 
*************************** 2. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: tasks 
    partitions: NULL 
     type: eq_ref 
possible_keys: PRIMARY,tasks_milestone_id_foreign 
      key: PRIMARY 
     key_len: 4 
      ref: fusion.task_wishlist.task_id 
     rows: 1 
    filtered: 10.00 
     Extra: Using where 
*************************** 3. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: milestones 
    partitions: NULL 
     type: eq_ref 
possible_keys: PRIMARY,milestones_project_id_foreign 
      key: PRIMARY 
     key_len: 4 
      ref: fusion.tasks.milestone_id 
     rows: 1 
    filtered: 100.00 
     Extra: NULL 
*************************** 4. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: projects 
    partitions: NULL 
     type: eq_ref 
possible_keys: PRIMARY 
      key: PRIMARY 
     key_len: 4 
      ref: fusion.milestones.project_id 
     rows: 1 
    filtered: 10.00 
     Extra: Using where 
4 rows in set, 1 warning (0.00 sec) 

クエリ3:削除projects.active = 1

SELECT `tasks`.*, 
     task_wishlist.description AS item_description, 
     task_wishlist.created_at AS item_created_at 
FROM `tasks` 
LEFT JOIN `task_wishlist` ON `tasks`.`id` = `task_wishlist`.`task_id` 
LEFT JOIN `milestones` ON `tasks`.`milestone_id` = `milestones`.`id` 
LEFT JOIN `projects` ON `milestones`.`project_id` = `projects`.`id` 
WHERE `task_wishlist`.`wishlist_id` = '527021' 
    AND `tasks`.`active` = '1' 
    /*AND `projects`.`active` = '1'*/ 
    AND `milestones`.`active` = '1' 
ORDER BY `task_wishlist`.`created_at` DESC 
LIMIT 25; 
/* Affected rows: 0 Found rows: 25 Warnings: 0 Duration for 1 query: 0.027 sec. (+ 4.031 sec. network) */ 

クエリ3説明

*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: task_wishlist 
    partitions: NULL 
     type: ref 
possible_keys: task_wishlist_wishlist_id_foreign,task_wishlist_task_id_foreign 
      key: task_wishlist_wishlist_id_foreign 
     key_len: 4 
      ref: const 
     rows: 7224 
    filtered: 100.00 
     Extra: Using index condition; Using where; Using filesort 
*************************** 2. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: tasks 
    partitions: NULL 
     type: eq_ref 
possible_keys: PRIMARY,tasks_milestone_id_foreign 
      key: PRIMARY 
     key_len: 4 
      ref: fusion.task_wishlist.task_id 
     rows: 1 
    filtered: 10.00 
     Extra: Using where 
*************************** 3. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: milestones 
    partitions: NULL 
     type: eq_ref 
possible_keys: PRIMARY 
      key: PRIMARY 
     key_len: 4 
      ref: fusion.tasks.milestone_id 
     rows: 1 
    filtered: 10.00 
     Extra: Using where 
*************************** 4. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: projects 
    partitions: NULL 
     type: eq_ref 
possible_keys: PRIMARY 
      key: PRIMARY 
     key_len: 4 
      ref: fusion.milestones.project_id 
     rows: 1 
    filtered: 100.00 
     Extra: Using index 
4 rows in set, 1 warning (0.00 sec) 

私はこのクエリが含まれるすべてのactiveフィールドで適切に実行させるために何ができますか?

+0

これらの各フィールドに一意でないインデックスを作成して、それがまったく役立つかどうかを確認しましたか? – ekalyvio

+0

この形式の説明は読みにくいですが、MySQLが扱う行の量は少ないです。これは、I/Oの問題がある可能性があることを意味します。機械的なハードドライブとデフォルトのMySQL設定を実行していますか? MySQLには、プロファイリングと呼ばれる追加のプロファイリングメカニズムがあります。 'SET PROFILING = 1;あなたの質問はここにあります。クエリー1のプロフィールを表示する。 SET PROFILING = 0; '。これにより、MySQLが舞台裏で行うすべてのステップが表示されます。盲目的に推測すると、あなたの 'innodb_buffer_pool_size'が低すぎるので、MySQLはHDDがI/Oを完了するのを待つ必要があります。これは遅いです。 – Mjh

+0

テーブルとインデックスの定義は何ですか? –

答えて

2

実際にあなたが照会する必要がある事実は、あなたのクエリが実際に単純なINNER JOINを実行していて、LEFT JOINSを実行していないことです。
は、基本的に内部ジョインと同じように動作します。ジョイン条件が「正しい」テーブル内で一致するローを見つけられなかった場合、NULLを返します。LEFT JOIN task_wishlistから

FROM `tasks` 
LEFT JOIN `task_wishlist` ON `tasks`.`id` = `task_wishlist`.`task_id` 
LEFT JOIN `milestones` ON `tasks`.`milestone_id` = `milestones`.`id` 
LEFT JOIN `projects` ON `milestones`.`project_id` = `projects`.`id` 
WHERE `task_wishlist`.`wishlist_id` = '527021' 
    AND `tasks`.`active` = '1' 
    AND `milestones`.`active` = '1' 
    AND `projects`.`active` = '1' 
  • ヌルがLEFT JOIN milestonesからWHERE task_wishlist.wishlist_id = '527021'
  • ヌルによって除外されているが除外されています
    しかし、あなたのクエリ内のすべてのNULLは、WHERE句の条件によって除外され、密接にクエリを調べてください。 WHERE milestones.active = '1'によってLEFT JOIN projectsから
  • ヌルはWHERE projects.active = '1'
によって除外され

MySQLはそれを認識しており、それが内部的にINNERにあなたのクエリは、クエリのJOIN書き換えて:あなたはWHERE句から(コメント)いくつかの条件を削除する場合

FROM `tasks` 
INNER JOIN `task_wishlist` ON `tasks`.`id` = `task_wishlist`.`task_id` 
INNER JOIN `milestones` ON `tasks`.`milestone_id` = `milestones`.`id` 
INNER JOIN `projects` ON `milestones`.`project_id` = `projects`.`id` 
WHERE `task_wishlist`.`wishlist_id` = '527021' 
    AND `tasks`.`active` = '1' 
    AND `milestones`.`active` = '1' 
    AND `projects`.`active` = '1' 

、これはLEFTを対応する「アクティブ」は一部のJOINクエリのセマンティクスが変更され、結果セットも変更されます。これらのクエリのパフォーマンスを比較するのは意味がありません。なぜなら、それらは率直に異なり、実際にはリンゴとオレンジを比較しているからです。


クエリは、単純な内部結合やっているので、あなたはこの1にそれを書き換えることができます:あなた上記の条件で

FROM `tasks` 
INNER JOIN `task_wishlist` ON `tasks`.`id` = `task_wishlist`.`task_id` 
             AND `task_wishlist`.`wishlist_id` = '527021' 

INNER JOIN `milestones` ON `tasks`.`milestone_id` = `milestones`.`id` 
               AND `milestones`.`active` = '1' 

INNER JOIN `projects` ON `milestones`.`project_id` = `projects`.`id` 
               AND `projects`.`active` = '1' 

と今を簡単に中に使用される列の「ペア」を参照してくださいすることができますA参加:

  • projects.id + projects.active
  • milestones.id + milestones.active
  • task_wishlist.task_id + task_wishlist.wishlist_id

projectsテーブルのために、そこに "ペア" に一例をmulticolumのインデックスを追加してください:

CREATE INDEX xxx ON projects(id, active) 

id列が主キーである場合、それは
あなた自身を実験しなければならないので、複数列の代わりに単一のactive列にのみ索引を追加することができます。

+0

哲学的には、「ON」はテーブルどうしがどのように関係しているかを言うだけです。 'WHERE'はフィルタリングを含んでいなければなりません。 INNER JOINの場合、オプティマイザは気にしません。 LEFT JOINには意味的な違いがあります。 –

1

task_wishlistは、taskswishlistsの間の多対多マッピングテーブルです。私はまともなインデックスがないと確信しています。ここでのヒントに従ってください:

http://mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table

それはテーブルごとに、SHOW CREATE TABLEに戻ってくる、その後、十分ではない場合。