3

「orders_products」という名前の mySQL テーブルがあり、次の関連フィールドがあります。

  • products_id
  • orders_id

両方のフィールドにインデックスが付けられます。

次のクエリを実行しています。

SELECT products_id, count( products_id ) AS counter
FROM orders_products
WHERE orders_id
IN (
  SELECT DISTINCT orders_id
  FROM orders_products
  WHERE products_id = 85094
)
AND products_id != 85094
GROUP BY products_id
ORDER BY counter DESC
LIMIT 4

このクエリは非常に長く、約 20 秒かかります。それ以外の場合、データベースはあまりビジーではなく、他のクエリでうまく機能します。

疑問に思っているのですが、クエリが非常に遅くなる原因は何ですか?

テーブルがかなり大きい (約 1,500 万行、サイズ約 210 MB)、これはメモリの問題でしょうか?

mySQL に時間がかかっていることを正確に知る方法はありますか?

Explain の出力:

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   PRIMARY     orders_products     range   products_id     products_id     4   NULL    1577863     Using where; Using temporary; Using filesort
2   DEPENDENT SUBQUERY  orders_products     ref     orders_id,products_id   products_id     4   const   2   Using where; Using temporary
4

2 に答える 2

5

を使用するクエリはWHERE ID IN (subquery)、mysql で悪名高いパフォーマンスを発揮します。

ただし、このようなクエリのほとんどの場合、 として書き直すことができJOINます。これも例外ではありません。

SELECT
    t2.products_id,
    count(t2.products_id) AS counter
FROM orders_products t1
JOIN orders_products t2
    ON t2.orders_id = t1.orders_id
    AND t2.products_id != 85094 
WHERE t1.products_id = 85094
GROUP BY t2.products_id
ORDER BY counter DESC
LIMIT 4

他の製品がない行を返す(およびそれらの数をゼロに表示する) 場合は、結合を に変更しLEFT JOINます。

テーブルの最初のインスタンスに が含まれていることに注意してくださいWHERE products_id = X。これにより、インデックスのルックアップが可能になり、すぐに行数が減り、テーブルの 2 番目のインスタンスにはターゲット データがありますが、id フィールドをルックアップしました (これも高速です)。結合条件でフィルタリングして、他の製品をカウントします。

于 2013-07-11T10:22:33.157 に答える
1

これらを試してみてください:

  1. MySQL はサブクエリで IN を最適化しません - テーブルを結合します。
  2. あなたのクエリには!=、処理が非常に難しい条件が含まれています。製品を絞り込み、不等式比較ではなく複数のルックアップを使用できますか?
于 2013-07-11T10:24:34.640 に答える