SQL優化之外連接(一)

         前兩天接觸了一個項目,裏面的一個報表查詢功能,訪問數據庫很慢,嚴重時請求直接超時,寫的sql語句得有三四百行,真是頭疼,沒辦法,硬着頭皮,只能一段一段的分析sql,查詢sql慢的問題。解決思路就是使用EXPLAIN 命令來查看哪些表沒有用到索引。通過查找終於找到問題所在,現記錄如下:

1、問題所在:

join on 條件後面不能使用or連接,造成索引失效,會全表掃描。

sql語句實例:

SELECT
		sp.id,
		gcm.id AS gcmId,
		gcm.material_id
		FROM
		gt_supply_order sp
		LEFT JOIN gt_supply_order_material gm ON sp.id = gm.supply_order_id
		LEFT JOIN gt_contract gc ON sp.contract_id = gc.id
		left join gt_orderform_goods nm on nm.order_id=gc.id or nm.id=gm.order_form_goods_id
		LEFT JOIN gt_orderform_goods gcm ON gcm.id = nm.id
		OR gcm.main_contract_goods_id = nm.id
		AND gcm.deleted = 0
		WHERE
		sp.deleted = 0
		AND gm.deleted = 0
		AND sp.contract_id = #{jgMaterialSupplyVO.contractId} and sp.goods_class_name = #{jgMaterialSupplyVO.goodsName} and sp.supply_order_status_enum=4
		GROUP BY
		sp.id,gcm.id

2、解決方案:

上面查詢(join on or)可以用 union 替換(索引有效),缺點sql語句長(相比性能問題還是可取的)

中間有個小插曲:

union 操作會對結果去重且排序,union all 不會去重

優化後的SQL如下:

select  a.id,gcm.id AS gcmId,gcm.material_id from(
 SELECT
  sp.id,
    nm.id as nmid
  FROM
  gt_supply_order sp
  LEFT JOIN gt_supply_order_material gm ON sp.id = gm.supply_order_id
  LEFT JOIN gt_contract gc ON sp.contract_id = gc.id
  left join gt_orderform_goods nm on nm.order_id=gc.id  
 WHERE
  sp.deleted = 0
  AND gm.deleted = 0 AND nm.deleted=0
   AND sp.contract_id = 137957291194000 and sp.goods_class_name = '橋樑支座' and sp.supply_order_status_enum=4
 union
  SELECT
  sp.id,
  nm.id as nmid
  FROM
  gt_supply_order sp
  LEFT JOIN gt_supply_order_material gm ON sp.id = gm.supply_order_id
  LEFT JOIN gt_contract gc ON sp.contract_id = gc.id
  left join gt_orderform_goods nm on  nm.id=gm.order_form_goods_id
 WHERE
  sp.deleted = 0
  AND gm.deleted = 0 AND nm.deleted=0
   AND sp.contract_id = 137957291194000 and sp.goods_class_name = '橋樑支座' and sp.supply_order_status_enum=4
)a
 LEFT JOIN gt_orderform_goods gcm ON gcm.id = a.nmid 
where gcm.id IS NOT NULL
GROUP BY a.id,gcm.id
union
select  b.id,gcm.id AS gcmId,gcm.material_id from 
(
 SELECT
  sp.id,
    nm.id as nmid
  FROM
  gt_supply_order sp
  LEFT JOIN gt_supply_order_material gm ON sp.id = gm.supply_order_id
  LEFT JOIN gt_contract gc ON sp.contract_id = gc.id
  left join gt_orderform_goods nm on nm.order_id=gc.id  

 WHERE
  sp.deleted = 0
  AND gm.deleted = 0 AND nm.deleted=0
   AND sp.contract_id = 137957291194000 and sp.goods_class_name = '橋樑支座' and sp.supply_order_status_enum=4
 union
  SELECT
 sp.id,
  nm.id as nmid
  FROM
  gt_supply_order sp
  LEFT JOIN gt_supply_order_material gm ON sp.id = gm.supply_order_id
  LEFT JOIN gt_contract gc ON sp.contract_id = gc.id
  left join gt_orderform_goods nm on nm.id=gm.order_form_goods_id
 WHERE
  sp.deleted = 0
  AND gm.deleted = 0 AND nm.deleted=0
   AND sp.contract_id = 137957291194000 and sp.goods_class_name = '橋樑支座' and sp.supply_order_status_enum=4
)b
 LEFT JOIN gt_orderform_goods gcm ON  gcm.main_contract_goods_id = b.nmid 
where gcm.id IS NOT NULL
 GROUP BY
  b.id,gcm.id

 

3、總結:

(1)通過上面的優化,查詢速度由原來的77秒,提速到了0.107秒,提高700多倍,可見,SQL優化是多麼的重要呀。

(2)這種優化方式可能不是最優的(sql語句太長),如有高人還有其他優化方式,希望可以交流,謝謝。

(3)有興趣的小夥伴可以測試下,歡迎交流。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章