php - 求这个sql怎么优化下
世界只因有你
世界只因有你 2017-05-16 13:13:12
0
2
702

sql语句是:
explain SELECT bp.amount / (select count(*) from yd_order_product where order = bp.order and product = bp.product) as amount,s.costprice as price,s.store,b.type from yd_batch_product as bp left join yd_order_product as op on op.order = bp.order and op.product = bp.product left join yd_batch as b on bp.batch = b.id left join yd_order as o on bp.order = o .id left join yd_stock as s on bp.product = s.id where o.deleted = '0' and s.forbidden = '0' and b.createdDate between '2015-10-13 00:00:00' and '2017-04-30 23:59:59' and s.store in (1,2,3,4,5,6) and s.chainID = 1

请问下这个第一行的type值为什么会是ALL

世界只因有你
世界只因有你

reply all(2)
巴扎黑

@TroyLiu ,你给的建议,创建的索引太多了,建立order/product/batch/amount组合索引的思路感觉不对。

sql优化的核心思路是,对大数据的表能够尽量根据已有的where语句中的条件对数据进行过滤,在这个例子中:
yd_batch_product表的数量量应该是最大的,但在where语句中没有过滤条件,导致执行效率较差。

出现“Using temporary; Using filesort”的原因是,group by中的字段,不完全在第一个表yd_batch_product表字段范围内。

建议:
1、yd_batch/yd_order/yd_stock用的是LEFT JOIN,但是在where语句中有这些表字段的过滤条件,因此和INNER JOIN是等价的,因此连接方式可以改成INNER JOIN,这样mysql在判断执行计划的时候,就不是只能先查询yd_batch_product 表了。
2、yd_batch表的createdDate字段建立索引,看执行计划中第一个驱动表是否有变化,如果createdDate的条件过滤性很强,执行计划中第一个表应该是yd_batch。
3、yd_stock表,如何store和chainID组合后过滤性强,可以建立组合索引,和上一步同样判断执行计划是否有变化。

当然,最理想的情况是从业务和数据出发,能找出yd_batch_product表上能大量过滤数据的条件,然后根据这个条件创建索引。如yd_batch表的createdDate字段在yd_batch_product表上也有类似的冗余字段,就使用这个字段创建索引。


更新问题后的建议:
1、TYPE=ALL表示用的是全表扫描,虽然createdDate已经创建索引,但数据库评估后认为使用全表扫描的成本更低,总体上认为是正常(createdDate的范围较大,含一年多数据数,共1万多条)。如果想用索引可以把范围缩小的几天内,看执行计划是否有变化。当然也可以使用提示强制使用索引,但效率就不一定高了。
2、yd_order_product表查询了两次,尤其是在执行计划中select的子查询,应该尽量避免。

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!