3

すべてのテーブルが比較的小さく (約 2,000 行) あるにもかかわらず、このクエリは 12 秒以上実行されます。

SELECT attr_73206_ AS attr_73270_ 
 FROM object_73130_ f1 
 LEFT OUTER JOIN (
   SELECT id_field, attr_73206_ FROM (
     SELECT m.id_field, t0.attr_73102_ AS attr_73206_ FROM object_73200_ o
     INNER JOIN master_slave m ON (m.id_object = 73130 OR m.id_object = 73290) AND (m.id_master = 73200 OR m.id_master = 73354) AND m.id_slave_field = o.id 
     INNER JOIN object_73101_ t0 ON t0.id = o.attr_73206_ 
     ORDER BY o.id_order 
   ) AS o GROUP BY o.id_field 
 ) AS o ON f1.id = o.id_field

どちらのテーブルにもid、主キーとしてフィールドがあります。また、id_fieldid_orderattr_73206_および のすべてのフィールドにmaster_slaveインデックスが付けられます。このクエリのロジックに関しては、全体としてマスター/ディテールのようなものです。表object_73130_はマスター表、表object_73200_はディテール表です。それらはmaster_slaveテーブルによってリンクされています。ID によってobject_73101_フィールドの実際の値を取得するために使用されるアドホック テーブルです。attr_73206_マスター テーブルの各行に対して、クエリはディテール テーブルの最初の行からフィールドを返します。まず、クエリの外観が変わりましたが、ここでスタックオーバーフローで、このより最適化された構造を使用するようにアドバイスされました (以前に使用されていたサブクエリの代わりに、ところで、クエリがはるかに高速に実行されるようになりました)。最初のサブクエリがJOINblock は非常に高速に実行されますが、メインのマスター テーブルの行数に匹敵する行数が返されます。いずれにせよ、私はそれを最適化する方法がわかりません。単純な高速実行の結合がなぜこれほど多くの問題を引き起こすのか疑問に思っています。ああ、主な観察結果は、クエリからアドホックを削除しobject_73101_て ID のみを返し、実際の値を返さない場合、クエリはフラッシュと同じくらい速く実行されるということです。そのため、すべての注意はクエリのこの部分に集中する必要があります

INNER JOIN object_73101_ t0 ON t0.id = o.attr_73206_

クエリ全体がひどく遅くなるのはなぜですか?

編集

このようにして、超高速で実行されます

SELECT t0.attr_73102_ AS attr_73270_ 
FROM object_73130_ f1 
LEFT OUTER JOIN (
SELECT id_field, attr_73206_ FROM (
    SELECT m.id_field, attr_73206_ FROM object_73200_ o
    INNER JOIN master_slave m ON (m.id_object = 73130 OR m.id_object = 73290)  AND (m.id_master = 73200 OR m.id_master = 73354) AND m.id_slave_field = o.id 
    ORDER BY o.id_order 
) AS o GROUP BY o.id_field 
) AS o ON f1.id = o.id_field
LEFT JOIN object_73101_ t0 ON t0.id = o.attr_73206_ 

したがって、アドホック結合をサブクエリの外側に配置しただけであることがわかります。しかし、問題は、サブクエリが自動的に作成され、それを作成するアルゴの部分にアクセスでき、このアルゴを変更でき、クエリ全体を構築するアルゴの部分にアクセスできないことです。私にできることは、サブクエリを何とか修正することだけです。INNER JOINとにかく、サブクエリ内でクエリ全体が何百倍も遅くなる理由をまだ理解できません。

編集

テーブルごとに異なるエイリアスを持つ新しいバージョンのクエリ。これはパフォーマンスには影響しません。

SELECT attr_73206_ AS attr_73270_ 
FROM object_73130_ f1 
LEFT OUTER JOIN (
SELECT id_field, attr_73206_ FROM (
    SELECT m.id_field, t0.attr_73102_ AS attr_73206_ FROM object_73200_ a
    INNER JOIN master_slave m ON (m.id_object = 73130 OR m.id_object = 73290)  AND (m.id_master = 73200 OR m.id_master = 73354) AND m.id_slave_field = a.id 
    INNER JOIN object_73101_ t0 ON t0.id = a.attr_73206_ 
    ORDER BY a.id_order 
) AS b GROUP BY b.id_field 
) AS c ON f1.id = c.id_field

編集

これはEXPLAINコマンドの結果です:

| id | select_type  |  TABLE  |  TYPE  | possible_keys         |     KEY     | key_len  |   ROWS  |  Extra                          |
| 1  |  PRIMARY     |   f1    |  INDEX |  NULL                 |    PRIMARY  |   4      |  1570   | USING INDEX
| 1  |  PRIMARY     | derived2|  ALL   |  NULL                 |    NULL     |  NULL    |  1564   |
| 2  |  DERIVED     | derived3|  ALL   |  NULL                 |    NULL     |  NULL    |  1575   | USING TEMPORARY; USING filesort
| 3  |  DERIVED     | m       | RANGE  | id_object,id_master,..|   id_object |   4      |  1356   | USING WHERE; USING TEMPORARY; USING filesort 
| 3  |  DERIVED     | a       | eq_ref | PRIMARY,attr_73206_   |   PRIMARY   |   4      |    1    |
| 3  |  DERIVED     | t0      | eq_ref | PRIMARY               |   PRIMARY   |   4      |    1    |

それの何が問題なのですか?

編集

EXPLAIN「超高速」クエリのコマンドの結果は次のとおりです

| id | select_type  |  TABLE  | TYPE  | possible_keys        |     KEY     | key_len  |   ROWS  |  Extra                          
| 1  |  PRIMARY     |   f1    | INDEX | NULL                 |    PRIMARY  |   4      |  1570   | USING INDEX
| 1  |  PRIMARY     | derived2| ALL   | NULL                 |    NULL     |  NULL    |  1570   |
| 1  |  PRIMARY     | t0      | eq_ref| PRIMARY              |    PRIMARY  |   4      |  1      | 
| 2  |  DERIVED     | derived3| ALL    | NULL                |   NULL      |   NULL   |  1581   | USING TEMPORARY; USING filesort 
| 3  |  DERIVED     | m       | RANGE  | id_object,id_master,|   id_bject  |   4      |  1356   | USING WHERE; USING TEMPORARY; USING filesort
| 3  |  DERIVED     | a       | eq_ref | PRIMARY             |   PRIMARY   |   4      |    1    |

閉まっている

上で示した独自の「超高速」クエリを使用します。もう最適化は無理だと思います。

4

1 に答える 1

1

データ/クエリの正確な性質を知らなくても、私が見ていることがいくつかあります。

  1. MySQL は派生テーブルの作成を必要とするため、副選択の処理が苦手なことで有名です。実際、MySQL の一部のバージョンでは、サブセレクトの使用時にインデックスも無視されます。通常、副選択の代わりに JOIN を使用することをお勧めしますが、副選択を使用する必要がある場合は、その副選択をできるだけ無駄のないものにすることをお勧めします。

  2. ORDER BY を副選択に入れる特別な理由がない限り、結果セットが小さくなる可能性があるため (より迅速な並べ替えが可能になる)、「メイン」クエリ部分に移動することをお勧めします。

そうは言っても、JOINロジックを使用してクエリを書き直そうとしましたが、最終的な値(attr_73102_)がどのテーブルから来ているのか疑問に思っていましたか?それは副選択の結果ですか、それともテーブル object_73130_ からのものですか? サブセレクトからのものである場合、サブセレクトから値のリストのみを返し、一致しない行には NULL を返すため、元の LEFT JOIN に悩まされている理由がわかりませんobject_73130_ から。

とにかく、この答えを知らなくても、以下のクエリは構文的に同等である可能性があると思います。

SELECT t0.attr_73102_ AS attr_73270_ 
FROM object_73130_ f1 
LEFT JOIN (object_73200_ o
  INNER JOIN master_slave m ON m.id_slave_field = o.id
  INNER JOIN object_73101_ t0 ON t0.id = o.attr_73206_)
ON f1.id = o.id_field
WHERE m.id_object IN (73130,73290) 
AND m.id_master IN (73200,73354) 
GROUP BY o.id_field
ORDER BY o.id_order;
于 2013-09-03T17:34:37.953 に答える