記一次mysql多表查詢(left jion)優化案例


一次mysql多表查詢(left jion)優化案例

在新上線的供需模塊中,發現某一個查詢按鈕點擊后,出不來結果,找到該按鈕對應sql手動執行,發現需要20-30秒才能出結果,所以服務端程序判斷超時,故先不顯示結果
以下是對這條查詢的優化記錄

1 數據庫配置

數據庫配置:4C8G
主表數據:3W+

2 sql語句

提取sql語句,簡化如下

SELECT
	taba.id,
	taba.title,
	taba.type,
	taba.end_time,
	tabb.username,
	tabc.orgname
FROM
	taba
LEFT JOIN tabd ON tabd.info_id = taba.id
LEFT JOIN tabe ON tabe.sdo_id = taba.id
LEFT JOIN tabb ON tabb.id = taba.creator
LEFT JOIN tabc ON tabc.id = taba.organization_id
WHERE
	taba.`STATUS` = 'PUBLISH'
AND tabd.type = 'INDEX'
AND tabd.`VALUE` = '1'
AND taba.info_type = 'SUPPLY'
GROUP BY
	taba.id
ORDER BY
	taba.create_time DESC
LIMIT 100

3 優化記錄

3.1 數據庫索引

首先第一反應,查sql是否走了索引

EXPLAIN
select ......

從索引檢查結果發現

  1. tabe只有主鍵索引,沒有sdo_id的索引
    經過確定sdo_id是通過uuid制作,重復數很少,可以增加上索引
  2. 其他條件雖然也沒走索引,但是屬於枚舉值,重復性高,沒有加索引的條件

經過添加索引,數據查詢時間降低到3秒以內,所以正確的索引才是王道

3.2 返回數據限制

經過與開發人員溝通,確定可以每次只取10條數據,所以要求他們更改limit語句限制為limit 10

經過修改limit語句,數據庫直插時間已經變味1.7秒

3.3 spring框架錯誤的conut *

經過前兩部優化,按理2秒左右app就能顯示數據,但是時間上卻需要4秒鍾
通過sql慢查詢日志,發現在這條sql執行前,spring框架自動執行了一個select count(0) from (......)的操作來做分頁,但是所以導致查詢時間是理論上的2倍
再次與開發確定,不用框架的自動分頁功能,改為代碼層手動分頁

結果修改框架的分頁,app查詢時間達到2秒內,已基本得到解決

3.4 極限優化limit

查詢優化到2秒,已基本可以接受,但是先到數據才3萬多行,感覺還是不能接受,繼續找原因,發現如下:

  • 3萬+數據,但是sql執行結果卻顯示掃描了100多萬行數據

觀察sql語句,可以發現是先做了多次left join后,對結果取limit,那能不能先取limit 10再進行查詢呢,於是把sql優化如下

SELECT
	taba.id,
	taba.title,
	taba.type,
	taba.end_time,
	tabb.username,
	tabc.orgname
FROM
	taba
LEFT JOIN tabd ON tabd.info_id = taba.id
LEFT JOIN tabe ON tabe.sdo_id = taba.id
LEFT JOIN tabb ON tabb.id = taba.creator
LEFT JOIN tabc ON tabc.id = taba.organization_id
WHERE
	tabd.type = 'INDEX'
AND tabd.`VALUE` = '1'
AND taba.id IN (
	SELECT * FROM
		( SELECT id FROM taba WHERE	`STATUS` = 'PUBLISH'
			AND info_type = 'SUPPLY'
			ORDER BY taba.create_time DESC	LIMIT 10 ) AS tmp
)

優化方法:

  • 將limit語句通過子查詢放入where條件中
  • sql將先執行子查詢獲取10條id數據
  • 讓后將10條id拿去前面做join

優化結果

  • sql執行時間達到0.117秒,再一次質的飛躍
  • 基本做到秒加載,點擊按鈕,一秒內出結果

3.4.1

第二天一覺醒來,覺得這個sql還有值得優化的地方,於是分別提取出各語句執行后,發現耗時最長的是limit條件,耗時0.09s

優化方法

  • 查找發現原因是order by條件create_time列未加索引,導致做了一次全表掃描
  • 於是增加上create_time索引

優化結果

  • sql執行時間變為0.068s
  • 再次說明正確的索引才是王道

3.5 優化后記

其實sql中還有幾個可以優化的地方,比如:

  • 4個left join中的3個可以改成inner join
  • 原語句的group by,經測試改掉可優化0.3秒(1.7秒處)
  • limit語句可以放到from處先處理等

但是:

  • sql優化是長期的過程
  • 優先解決影響業務的慢查詢
  • 優先解決占時間比例大的慢查詢
  • 咱是運維,不是DBA,還有高可用等着我玩
  • 因此已經達到要求,甚至超額完成,就不用再管芝麻了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM