记一次SQL优化

业务查询缓慢,要求优化查询速度,优化步骤一一枚举出来,防止忘了。

 

总结:

  1、尽量让SQL都使用索引,不要存在in这种不走索引的写法

  2、适当的时候,可以将子查询优化成为表连接

 

原SQL:

复制代码
SELECT
 tab2.quoteOrderId,
 tab2.quoteOrderNumber,
 tab2.userUpdateTpye,
 tab2.quoteTitle,
 DATE_FORMAT( tab2.quoteClosingDate, '%Y-%m-%d' ) AS quoteClosingDate,
 DATE_FORMAT( tab2.expectedReceivingDate, '%Y-%m-%d' ) AS expectedReceivingDate,
 tab2.totalPrice,
 tab2.quoteDate,
 tab2.user_id AS clientCompany,
 tab2.type 
FROM
 (
 SELECT
  tab.quoteOrderId,
  tab.quoteOrderNumber,
  tab.userUpdateTpye,
  tab.quoteTitle,
  tab.quoteClosingDate,
  tab.expectedReceivingDate,
  tab.totalPrice,
  tab.quoteDate,
  tab.user_id,
  ( CASE WHEN TAB.countNum = TAB.notApprovedCount THEN 0 WHEN TAB.countNum = adoptCount THEN 2 ELSE 1 END ) AS type 
 FROM
  (
  SELECT
   t1.id AS quoteOrderId,
   t1.quote_order_number AS quoteOrderNumber,
   t1.user_update_tpye AS userUpdateTpye,
   t1.quote_title AS quoteTitle,
   t1.quote_closing_date AS quoteClosingDate,
   t1.expected_receiving_date AS expectedReceivingDate,
   SUM( CASE WHEN t3.approval_status IS NULL THEN 1 ELSE 0 END ) AS notApprovedCount,
   SUM( CASE t3.approval_status WHEN '1' THEN 1 ELSE 0 END ) AS adoptCount,
   SUM( CASE t3.approval_status WHEN '2' THEN 1 ELSE 0 END ) AS refuseCount,
   count( 1 ) countNum,
   SUM(
   t2.amount * IFNULL( t3.bj_unit_price_including_tax, 0 )) AS totalPrice,
   t1.quote_date AS quoteDate,
   t4.user_id 
  FROM
   quote_order_info t1
   LEFT JOIN quote_order_pro_info t2 ON t1.id = t2.quote_order_info_id
   LEFT JOIN quote_bj_order_pro_info t3 ON t3.id IN ( SELECT MAX( id ) FROM quote_bj_order_pro_info WHERE quote_order_pro_info_id = t2.id GROUP BY quote_order_pro_info_id ) 
   AND t3.approval_status = 1
   LEFT JOIN quote_order_user_info t4 ON t4.quote_order_info_id = t1.id 
  GROUP BY
   t1.id,
   t4.user_id 
  ) AS tab 
 ) AS tab2
复制代码

 

简单理解sql,业务sql嵌套较多,拆分sql,分段,感觉外层无法优化,也就是说优化点要集中在内层sql:

复制代码
SELECT
   t1.id AS quoteOrderId,
   t1.quote_order_number AS quoteOrderNumber,
   t1.user_update_tpye AS userUpdateTpye,
   t1.quote_title AS quoteTitle,
   t1.quote_closing_date AS quoteClosingDate,
   t1.expected_receiving_date AS expectedReceivingDate,
   SUM( CASE WHEN t3.approval_status IS NULL THEN 1 ELSE 0 END ) AS notApprovedCount,
   SUM( CASE t3.approval_status WHEN '1' THEN 1 ELSE 0 END ) AS adoptCount,
   SUM( CASE t3.approval_status WHEN '2' THEN 1 ELSE 0 END ) AS refuseCount,
   count( 1 ) countNum,
   SUM(
   t2.amount * IFNULL( t3.bj_unit_price_including_tax, 0 )) AS totalPrice,
   t1.quote_date AS quoteDate,
   t4.user_id 
  FROM
   quote_order_info t1
   LEFT JOIN quote_order_pro_info t2 ON t1.id = t2.quote_order_info_id
   LEFT JOIN quote_bj_order_pro_info t3 ON t3.id IN ( SELECT MAX( id ) FROM quote_bj_order_pro_info WHERE quote_order_pro_info_id = t2.id GROUP BY quote_order_pro_info_id ) 
   AND t3.approval_status = 1
   LEFT JOIN quote_order_user_info t4 ON t4.quote_order_info_id = t1.id 
  GROUP BY
   t1.id,
   t4.user_id 
复制代码

 

原sql速率:12.4s

发现问题1:

 

 

 圈出来的这个sql,in可以改为=号, 原因:分组条件是quote_order_pro_info_id ,且quote_order_pro_info_id有限制= t2.id,也就是说这个group by是多此一举,聚合得到的值只有一个

修正sql后:

LEFT JOIN quote_bj_order_pro_info t3 ON t3.id = ( SELECT MAX( id ) FROM quote_bj_order_pro_info WHERE quote_order_pro_info_id = t2.id )

查询速率:0.175s

 

优化点2:子查询优化为表连接

子查询会导致外层查询使用不到索引

提取步骤:

  提取到与t3同级,也就是与t2同级,使用的t2的条件就应该变为join 的on 条件,因此除了查询出max(id)之外,分组条件 quote_order_pro_info_id 也要查询出来作为连接条件

  t3 的id = 查询列的maxId,则是t3关联t5的关联列在on中体现

修正后sql:

   left join (SELECT MAX(id) maxId, quote_order_pro_info_id  FROM quote_bj_order_pro_info group by quote_order_pro_info_id) t5 on t5.quote_order_pro_info_id = t2.id
   LEFT JOIN quote_bj_order_pro_info t3 ON t3.id = t5.maxId 
   AND t3.approval_status = 1

查询速率:0.068s

 

 

欢迎朋友有有趣的案例发表出来一起探讨

  

posted @   guodaxia  阅读(76)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 字符编码:从基础到乱码解决
历史上的今天:
2016-04-14 hibernate多对一和一对多关联
2016-04-14 hibernate单向关联与双向关联的区别(原)
点击右上角即可分享
微信分享提示