我如何优化这个子查询?

Posted

技术标签:

【中文标题】我如何优化这个子查询?【英文标题】:How I can optimize this subquery? 【发布时间】:2017-09-28 09:09:54 【问题描述】:

我编写了一个带有连接和子查询的查询。它的执行需要 2 分钟。优化不了怎么办?有什么建议吗?

select oli.*,oli2.* from order o
LEFT JOIN order_line_item oli ON oli.order_id = o.id
LEFT JOIN order_line_item oli2 ON oli2.id 
= (SELECT oli3.id FROM order_line_item oli3
WHERE oli3.order_id = o.id
AND oli.code = oli3.alternative
GROUP BY oli3.code, o.id
LIMIT 1)  WHERE o.store_id != 100 GROUP BY oli.code, oli2.code, o.id

我的子查询可以正常工作,但需要花费太多时间。实际上,它找到了替代产品。如何优化我的子查询?

【问题讨论】:

请为您的查询中涉及的所有表提供SHOW CREATE TABLE <tablename> 输出。 还有,有必要选择*吗?如果您不需要所有列,则可能会根据我们从您的表结构(评论上方)中了解到的内容以及您确实需要的列进行改进。 因为*,这听起来像是对GROUP BY 的无效使用。 请用英文解释查询的目的。 (这个查询太复杂了,我无法理解。我认为可能有更简单的方法来处理它。) 认为有订单。该订单有 11 个项目(产品)存储在订单行项目表中。一种产品已完成,系统具有该成品的替代产品。我必须分别计算给客户的产品数量和替代产品的数量。产品的alternated_to 列分配给替代产品的代码。所以我使用了oli.code = oli3.alternative。它工作正常,但我的子查询花费了太多时间@RickJames 【参考方案1】:

oli2 ON 中的子查询是导致运行缓慢的原因,因为它需要为每一行执行。可以简化为:

SELECT
    oli.*,
    oli2.* 
FROM order o

LEFT JOIN order_line_item oli 
ON oli.order_id = o.id

LEFT JOIN order_line_item oli2 
ON (
    o.id = oli2.order_id
    AND 
    oli.code = oli2.alternative
)

WHERE o.store_id != 100 

GROUP BY oli.code, oli2.code, o.id

【讨论】:

谢谢,但还是很慢【参考方案2】:

code 上的索引可能因为“前缀”而无用。 (请提供EXPLAIN SELECT ...确认。`)

“5.6 中的 767 限制”有多种解决方法; “191 修复”对于您的情况可能是最糟糕的。我的Limits blog 列出了您的修复和其他 4 个:

升级到 5.7.7 以获得 3072 字节的限制——您的云可能不提供此功能; 在 VARCHAR 上将 255 更改为 191 -- 您会丢失任何超过 191 个字符的值(不太可能?); ALTER .. CONVERT TO utf8 -- 你失去了表情符号和一些中文; (您当前的修复)使用“前缀”索引——您会失去一些性能优势。 保留 5.6/5.5/10.1,但执行 4 个步骤将限制提高到 3072 字节(博客中的详细信息)。

请务必同时更改 codealternative。如果这个建议还不够,我会深入挖掘。

【讨论】:

以上是关于我如何优化这个子查询?的主要内容,如果未能解决你的问题,请参考以下文章

如何简化这个子查询?

mysql中主查询和子查询关系是啥?

4.1 查询性能优化

Mysql创建SQL子查询ALIAS

优化大型子表的日期查询:GiST 还是 GIN?

UDF 与子查询性能问题