LoginSignup
9
10

More than 3 years have passed since last update.

MySQL: インデックスなき派生テーブルをなくしてクエリ速度を改善

Last updated at Posted at 2020-07-02

環境

  • MySQL 5.7

インデックスなき <derived2>

MySQLで遅いクエリがあり、EXPLAIN してみると、

table type key
<derived2> ALL NULL

と表示され、インデックスがあたっていないテーブルがありました。

そのテーブルの行数が多かったので、結果としてクエリ速度が遅くなっていました。

原因の把握

<derived2> とは

上の <derived2> は、FROM句のサブクエリで生成された派生テーブル (derived table) です。

下の例だと、t1 が派生テーブルになります。

SELECT * FROM (SELECT * FROM t1) AS derived_t1;

インデックスがあたらない原因

サブクエリ内で GROUP BY が用いられた場合、生成される派生テーブルにはインデックがあたらないようです。

The subquery for the derived table t1 can not be merged because it has a GROUP BY clause. Hence, MySQL 5.7 will materialize the result of this subquery, scan the resulting temporary table, and do primary-keys looks-up directly on the orders table.

MySQL 5.7: Improved Performance of Queries with Derived Tables - MySQL Server Blog」より引用

つまり次のような場合、 derived_t1 にはインデックスはあたらない(はず)です。

SELECT price_total FROM (
  SELECT SUM(price) price_total FROM t1 
  INNER JOIN t2 ON t2.t1_id = t1.id
  GROUP BY t1.id
) AS derived_t1;

解決方法: INNER JOIN 句で GROUP BY

サブクエリ + GROUP BY」が問題なので、 GROUP BY を INNER JOIN 句に移動させ、サブクエリをなくします。

例えば、上と同じ例を使うと、次のようなSQL文になります。

SELECT SUM(price) price_total FROM t1 
INNER JOIN (
  SELECT price, t1_id FROM t2
  GROUP BY t1_id
) t2 ON t2.t1_id = t1.id

これでインデックスなき派生テーブルはなくなり、クエリ速度が改善されました。

まとめ

インデックスなき派生テーブルをなくすには、サブクエリはなくし、GROUP BY を INNER JOIN 句に寄せることが必要です。

References

9
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
10