3

给定的是一个名为“orders_products”的 mySQL 表,其中包含以下相关字段:

  • products_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 秒。否则数据库不是很忙,并且在其他查询上表现良好。

我想知道,是什么导致查询如此缓慢?

该表相当大(大约 150 万行,大小约为 210 mb),这可能是内存问题吗?

有没有办法准确地说出 mySQL 花了这么长时间的原因?

解释的输出:

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

众所周知,使用 mysql 的查询WHERE ID IN (subquery)性能很差。

然而,对于此类查询的大多数情况,可以将它们重写为 a 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,它允许索引查找并立即减少行数,表的第二个实例有目标数据,但它在 id 字段上查找(再次快速),但是在连接条件中过滤以计算其他产品。

于 2013-07-11T10:22:33.157 回答
1

试试这些:

  1. MySQL 不使用子查询优化 IN - 将表连接在一起。
  2. 您的查询包含!=很难处理的条件 - 您可以缩小产品范围并使用多个查找而不是不公平比较吗?
于 2013-07-11T10:24:34.640 回答