Mysql临时表特性_结合业务特性巧用临时表

拿到某开发sql如下SELECTp.products_idFROMproductsASpJOINproducts_to_categoriesASpcUSING(products_id)JOINcategoriesAScUSING(categories_id)JOINproducts_r

拿到某开发sql如下SELECT p.products_id FROM products AS p

JOIN products_to_categories AS pc USING(products_id)

JOIN categories AS c USING(categories_id)

JOIN products_realtime_quantity AS prq ON prq.sku_or_poa = p.products_model

WHERE products_status =1 AND categories_status =1 AND prq.msg != 'Temporary out stock.'

ORDER BY p.products_date_added DESC LIMIT 10

一般看到这种sql,在where中只有status类似的字段(可选择性非常低,数据两极分化非常明显)而且需要order by的语句,我们就应该想到使用force index(order_by_column)来进行优化.

explian+----+-------------+-------+--------+------------------------------+-------------------+---------+--------------------------------+--------+----------------------------------------------+

| id | select_type | table | type | possible_keys

| key

| key_len | ref

| rows | Extra

|

+----+-------------+-------+--------+------------------------------+-------------------+---------+--------------------------------+--------+----------------------------------------------+

| 1 | SIMPLE

| pc | index | PRIMARY,categories_id

| PRIMARY

| 8

| NULL

| 1009510 | Using index; Using temporary; Using filesort |

| 1 | SIMPLE

| p

| eq_ref | PRIMARY,products_model

| PRIMARY

| 4

| banggood_work.pc.products_id |

1 | Using where

|

| 1 | SIMPLE

| c

| eq_ref | PRIMARY

| PRIMARY

| 4

| banggood_work.pc.categories_id |

1 | Using where

|

| 1 | SIMPLE

| prq | ref | ix_prg_sku_or_poa,ix_prq_msg | ix_prg_sku_or_poa | 152

| banggood_work.p.products_model |

1 | Using where

|

+----+-------------+-------+--------+------------------------------+-------------------+---------+--------------------------------+--------+----------------------------------------------+

发现mysql优化器选择了pc表的主键,虽然使用了索引,但是进行了全索引扫描,效果还是不理想!

强制使用force index后,explainEXPLAIN

-> SELECT p.products_id FROM products AS p FORCE INDEX(products_date_added)

-> JOIN products_to_categories AS pc USING(products_id)

-> JOIN categories AS c USING(categories_id)

-> JOIN products_realtime_quantity AS prq ON prq.sku_or_poa = p.products_model

-> WHERE products_status =1 AND categories_status =1 AND prq.msg != 'Temporary out stock.'

-> ORDER BY p.products_date_added DESC LIMIT 10

-> ;

+----+-------------+-------+--------+------------------------------+---------------------+---------+--------------------------------+------+-------------+

| id | select_type | table | type | possible_keys

| key

| key_len | ref

| rows | Extra

|

+----+-------------+-------+--------+------------------------------+---------------------+---------+--------------------------------+------+-------------+

| 1 | SIMPLE

| p

| index | NULL

| products_date_added | 8

| NULL

| 1 | Using where |

| 1 | SIMPLE

| prq | ref | ix_prg_sku_or_poa,ix_prq_msg | ix_prg_sku_or_poa | 152

| banggood_work.p.products_model | 1 | Using where |

| 1 | SIMPLE

| pc | ref | PRIMARY,categories_id

| PRIMARY

| 4

| banggood_work.p.products_id | 1009 | Using index |

| 1 | SIMPLE

| c

| eq_ref | PRIMARY

| PRIMARY

| 4

| banggood_work.pc.categories_id | 1 | Using where |

+----+-------------+-------+--------+------------------------------+---------------------+---------+--------------------------------+------+-------------+

发现索引已经变成productsw_date_added,而执行时间,前者是2s,后者是0.003s.

这是我们一贯的优化方法,但是我们可以根据sql语句的特性和业务特性,结合临时表进行一些淫邪的优化,虽然并不通用,但是可以开阔sql优化者的思维。

我们可以看到这条语句是需要根据产品添加时间拿取符合(products_status =1 AND categories_status =1 AND prq.msg != 'Temporary out stock.')条件的10个最新上架产品.而我们知道,最新上架的产品一般状态都是不可能马上下架,而且对应的类别id也是可用,而且库存也是充足的(要不然何必上架),这个特性站到了99.9%以上.所以,我们利用这个特性,,先从产品表中找出不带任何条件的200个产品,放到临时表,然后再用临时表结果集,和拿取条件进行匹配,取出最新的10条.

(200条是一个参考值,根据各自的逻辑特性来取)

sql如下SELECT DISTINCT p.products_id FROM

(SELECT products_id,products_model,products_status,products_date_added

FROM products

ORDER BY products_date_added DESC LIMIT 200

) AS p

JOIN products_to_categories AS pc USING(products_id)

JOIN categories AS c USING(categories_id)

JOIN products_realtime_quantity AS prq ON prq.sku_or_poa = p.products_model

WHERE products_status =1 AND categories_status =1 AND prq.msg != 'Temporary out stock.'

ORDER BY products_date_added DESC LIMIT 10;

explain后发现| 1 | PRIMARY

| | ALL | NULL

| NULL

| NULL | NULL

| 200 | Using where; Using temporary; Using filesort |

| 1 | PRIMARY

| prq

| ref | ix_prg_sku_or_poa,ix_prq_msg | ix_prg_sku_or_poa | 152

| p.products_model

| 1 | Using where; Distinct

|

| 1 | PRIMARY

| pc

| ref | PRIMARY,categories_id

| PRIMARY

| 4

| p.products_id

| 1009 | Using index; Distinct

|

| 1 | PRIMARY

| c

| eq_ref | PRIMARY

| PRIMARY

| 4

| banggood_work.pc.categories_id | 1 | Using where; Distinct

|

| 2 | DERIVED

| products | index | NULL

| products_date_added | 8

| NULL

| 200 |

|

我们可以看到,已经利用products表中的products_date_added字段排序取出200条,整个sql语句变成一个只有200行的临时表驱动查询了,性能相对于原来的语句,提高上百倍!

执行时间大约是0.02s(可能比force index略慢)。

本文出自 “原下” 博客,请务必保留此出处

本文原创发布php中文网,转载请注明出处,感谢您的尊重!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值