SQL調優13連問,收藏好!
來源:撿田螺的小男孩
前言
大家好,我是田螺。
準備了SQL調優的13連問,內容非常幹!相信大家看完一定會有幫助的。
1.日常工作中,你是怎麼最佳化SQL的?
大家可以從這幾個維度回答這個問題:
分析慢查詢日誌 使用explain檢視執行計劃 索引最佳化 深分頁最佳化 避免全表掃描 避免返回不必要的資料(如 select
具體欄位而不是select*
)使用合適的資料型別(如可以使用 int
型別的話,就不要設計為varchar
)最佳化sql結構(如 join
最佳化等等)適當分批次進行 (如批次更新、刪除) 定期清理無用的資料 適當分庫分表 讀寫分離
2. 是否遇到過深分頁問題,如何解決
我們可以透過減少回表次數來最佳化。一般有標籤記錄法和延遲關聯法。
標籤記錄法
就是標記一下上次查詢到哪一條了,下次再來查的時候,從該條開始往下掃描。就好像看書一樣,上次看到哪裡了,你就摺疊一下或者夾個書籤,下次來看的時候,直接就翻到啦。
假設上一次記錄到100000,則SQL可以修改為:
select id,name,balance FROM account where id > 100000 limit 10;
這樣的話,後面無論翻多少頁,效能都會不錯的,因為命中了id
索引。但是這種方式有侷限性:需要一種類似連續自增的欄位。
延遲關聯法
延遲關聯法,就是把條件轉移到主鍵索引樹,然後減少回表。假設原生SQL是這樣的的,其中id
是主鍵,create_time
是普通索引
select id,name,balance from account where create_time> '2020-09-19' limit 100000,10;
使用延遲關聯法最佳化,如下:
select acct1.id,acct1.name,acct1.balance FROM account acct1 INNER JOIN
(SELECT a.id FROM account a WHERE a.create_time > '2020-09-19' limit 100000, 10)
AS acct2 on acct1.id= acct2.id;
最佳化思路就是,先透過idx_create_time
二級索引樹查詢到滿足條件的主鍵ID
,再與原表透過主鍵ID
內連線,這樣後面直接走了主鍵索引了,同時也減少了回表。
3. 聊聊explain執行計劃
當explain
與SQL
一起使用時,MySQL將顯示來自最佳化器的有關語句執行計劃的資訊。即MySQL
解釋了它將如何處理該語句,包括有關如何連線表以及以何種順序連線表等資訊。
一條簡單SQL,使用了explain
的效果如下:
一般來說,我們需要重點關注type、rows、filtered、extra、key
。
3.1 type
type表示連線型別,檢視索引執行情況的一個重要指標。以下效能從好到壞依次:system > const > eq_ref > ref > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
system:這種型別要求資料庫表中只有一條資料,是 const
型別的一個特例,一般情況下是不會出現的。const:透過一次索引就能找到資料,一般用於主鍵或唯一索引作為條件,這類掃描效率極高,,速度非常快。 eq_ref:常用於主鍵或唯一索引掃描,一般指使用主鍵的關聯查詢 ref : 常用於非主鍵和唯一索引掃描。 ref_or_null:這種連線型別類似於 ref
,區別在於MySQL
會額外搜尋包含NULL
值的行index_merge:使用了索引合併最佳化方法,查詢使用了兩個以上的索引。 unique_subquery:類似於 eq_ref
,條件用了in
子查詢index_subquery:區別於 unique_subquery
,用於非唯一索引,可以返回重複值。range:常用於範圍查詢,比如:between ... and 或 In 等操作 index:全索引掃描 ALL:全表掃描
3.2 rows
該列表示MySQL估算要找到我們所需的記錄,需要讀取的行數。對於InnoDB表,此數字是估計值,並非一定是個準確值。
3.3 filtered
該列是一個百分比的值,表裡符合條件的記錄數的百分比。簡單點說,這個欄位表示儲存引擎返回的資料在經過過濾後,剩下滿足條件的記錄數量的比例。
3.4 extra
該欄位包含有關MySQL如何解析查詢的其他資訊,它一般會出現這幾個值:
Using filesort:表示按檔案排序,一般是在指定的排序和索引排序不一致的情況才會出現。一般見於order by語句 Using index :表示是否用了覆蓋索引。 Using temporary: 表示是否使用了臨時表,效能特別差,需要重點最佳化。一般多見於group by語句,或者union語句。 Using where : 表示使用了where條件過濾. Using index condition:MySQL5.6之後新增的索引下推。在儲存引擎層進行資料過濾,而不是在服務層過濾,利用索引現有的資料減少回表的資料。
3.5 key
該列表示實際用到的索引。一般配合possible_keys
列一起看。
注意:有時候,explain
配合show WARNINGS;
(可以檢視最佳化後,最終執行的sql),效果更佳哦。
4.說說大表的最佳化方案
資料庫設計最佳化
合理的資料庫設計可以極大地提高查詢效率。我們在設計大表時,可以考慮拆分表、使用分割槽表、新增索引等方式來最佳化表結構。同時也要避免使用大量冗餘欄位、避免頻繁使用join查詢等操作。
索引最佳化
對於大表的查詢操作,索引最佳化是非常重要的一環。可以考慮增加或者修改索引、使用覆蓋索引、使用聯合索引等方式來提高查詢效率。同時也要注意定期清理冗餘的索引以及對於經常使用的查詢語句建立索引。
分割槽最佳化
將大表按照某個列分成多個分割槽表,每個分割槽表的資料量較小,可以提高查詢和更新的效能。分割槽表還可以幫助在維護表結構的同時,減少鎖表時間,提高併發處理能力。
資料清理歸檔
對於一些歷史資料或者無用資料,可以進行定期歸檔,避免資料過多造成SQL查詢效率降低。同時也要注意對於大表進行定期的資料備份以及緊急資料恢復的準備工作。
快取最佳化
對於一些經常被查詢的資料,可以使用快取最佳化。使用Redis
等快取中介軟體來快取常用的資料,以減少查詢資料庫的次數,提高查詢效率。
SQL語句最佳化
在編寫SQL查詢語句時,要儘可能地簡單明瞭,避免複雜的查詢語句,同時也要避免一些不必要的查詢操作。對於複雜的查詢語句,可以使用Explain
執行計劃來進行最佳化。同時也要注意避免使用OR
等耗費效能的運算子。
分庫分表
如果資料量千萬級別,需要考慮分庫分表哈。分庫分表相關知識點,可以看我之前這篇文章哈,我們為什麼要分庫分表?
5.哪些因素可能導致MySQL慢查詢?
慢查詢一般有以下這些原因:
大家有興趣可以看下。我之前寫的這篇文章哈:盤點MySQL慢查詢的12個原因
6.如何使用索引最佳化SQL查詢?
新增合適索引(在 where、group by、order by
等後面的欄位新增合適索引)選擇合適的索引型別 ( B-tree
索引適合範圍查詢、雜湊索引適合等值查詢)注意不適合加索引的場景(資料量少的表,更新頻繁的欄位,區分度低的欄位) 加索引的時候,需要考慮覆蓋索引,減少回表,考慮聯合索引的最左字首原則 explain
檢視SQL
的執行計劃,確認是否會命中索引。注意索引並不是越多越好,通常建議在單個表中不要超過5個索引。因為索引會佔用磁碟空間,索引更新代價高。
7.聊聊慢SQL的最佳化思路
檢視慢查詢日誌記錄,分析慢SQL explain分析SQL的執行計劃 profile 分析執行耗時 Optimizer Trace分析詳情 確定問題並採用相應的措施
7.1 檢視慢查詢日誌記錄,分析慢SQL
如何定位慢SQL呢、我們可以透過slow log來檢視慢SQL
。預設的情況下呢,MySQL資料庫是不開啟慢查詢日誌(slow query log
)呢。所以我們需要手動把它開啟。
檢視下慢查詢日誌配置,我們可以使用show variables like 'slow_query_log%'
命令,如下:
slow query log
表示慢查詢開啟的狀態slow_query_log_file
表示慢查詢日誌存放的位置
我們還可以使用show variables like 'long_query_time'
命令,檢視超過多少時間,才記錄到慢查詢日誌,如下:
long_query_time
表示查詢超過多少秒才記錄到慢查詢日誌。
我們可以透過慢查日誌,定位那些執行效率較低的SQL語句,重點關注分析。
7.2 explain檢視分析SQL的執行計劃
當定位出查詢效率低的SQL後,可以使用explain
檢視SQL
的執行計劃。
當explain
與SQL
一起使用時,MySQL將顯示來自最佳化器的有關語句執行計劃的資訊。即MySQL
解釋了它將如何處理該語句,包括有關如何連線表以及以何種順序連線表等資訊。
一條簡單SQL,使用了explain
的效果如下:
一般來說,我們需要重點關注type、rows、filtered、extra、key
。
7.3 profile 分析執行耗時
explain
只是看到SQL
的預估執行計劃,如果要了解SQL
真正的執行執行緒狀態及消耗的時間,需要使用profiling
。開啟profiling
引數後,後續執行的SQL
語句都會記錄其資源開銷,包括IO,上下文切換,CPU,記憶體
等等,我們可以根據這些開銷進一步分析當前慢SQL的瓶頸再進一步進行最佳化。
profiling
預設是關閉,我們可以使用show variables like '%profil%'
檢視是否開啟,如下:
可以使用set profiling=ON
開啟。開啟後,可以執行幾條SQL,然後使用show profiles
檢視一下。
show profiles
會顯示最近發給伺服器的多條語句,條數由變數profiling_history_size
定義,預設是15。如果我們需要看單獨某條SQL的分析,可以show profile
檢視最近一條SQL的分析。也可以使用show profile for query id
(其中id就是show profiles中的QUERY_ID)檢視具體一條的SQL語句分析。
除了檢視profile ,還可以檢視cpu和io,如上圖。
7.4 Optimizer Trace分析詳情
profile只能檢視到SQL的執行耗時,但是無法看到SQL真正執行的過程資訊,即不知道MySQL最佳化器是如何選擇執行計劃。這時候,我們可以使用Optimizer Trace
,它可以跟蹤執行語句的解析最佳化執行的全過程。
我們可以使用set optimizer_trace="enabled=on"
開啟開關,接著執行要跟蹤的SQL,最後執行select * from information_schema.optimizer_trace
跟蹤,如下:
大家可以檢視分析其執行樹,會包括三個階段:
join_preparation:準備階段 join_optimization:分析階段 join_execution:執行階段
7.5 確定問題並採用相應的措施
最後確認問題,就採取對應的措施。
多數慢SQL都跟索引有關,比如不加索引,索引不生效、不合理等,這時候,我們可以最佳化索引。 我們還可以最佳化SQL語句,比如一些in元素過多問題(分批),深分頁問題(基於上一次資料過濾等),進行時間分段查詢 SQl沒辦法很好最佳化,可以改用ES的方式,或者數倉。 如果單表資料量過大導致慢查詢,則可以考慮分庫分表 如果資料庫在刷髒頁導致慢查詢,考慮是否可以最佳化一些引數,跟DBA討論最佳化方案 如果存量資料量太大,考慮是否可以讓部分資料歸檔
我之前寫了一篇文章,有關於導致慢查詢的12個原因,大家看一下哈:盤點MySQL慢查詢的12個原因
8.一條sql執行過長的時間,你如何最佳化,從哪些方面入手?
這道面試題,其實跟慢SQl排查解決有點像,所以大家回答得時候,可以參考上一小節哈。我們可以從這幾個方面入手哈:
確定瓶頸 索引最佳化 最佳化SQL語句 資料庫引數最佳化 分析鎖的情況 資料庫硬體升級
確定瓶頸
首先,透過檢視MySQL日誌,慢查詢日誌,explain分析SQL的執行計劃,profile 分析執行耗時,Optimizer Trace分析詳情等操作,確定查詢執行的瓶頸在哪裡。只有確定了瓶頸,才能有針對性地進行最佳化。
索引最佳化
在確定了瓶頸之後,可以考慮透過增加索引來最佳化查詢效率。可以根據查詢語句的條件,增加相應的索引,從而加快查詢速度。但是索引也會帶來一些負面影響,如佔用磁碟空間,降低寫入效率等,所以需要根據具體情況權衡。
最佳化SQL語句
有些SQL語句本身可能存在一些問題,如join操作過於頻繁,使用了不必要的子查詢等,這些都會導致查詢效率低下。可以透過最佳化SQL語句來減少不必要的操作,從而提高查詢效率。
資料庫引數最佳化
資料庫引數也會影響查詢效率,可以透過修改資料庫引數來最佳化查詢效率,如修改記憶體快取大小、修改連線池大小等。不同的資料庫引數最佳化方式不同,需要根據具體情況進行調整。
分析鎖的情況
查詢執行時間過長有可能是由於鎖的問題導致的,需要分析查詢語句中是否存在鎖的問題,如果存在鎖的問題,可以考慮增加鎖的併發度,從而提高查詢效率。
資料庫硬體升級
如果以上方法都無法解決問題,可以考慮對資料庫硬體進行升級,如增加 CPU 數量、加快磁碟讀寫速度等,從而提高資料庫的整體效能。
9. 列舉一下,常用的資料庫設計最佳化技巧?
欄位儘量避免使用NULL 合理選擇資料型別 欄位選擇合適的長度 正確使用索引 儘量少定義text型別 合理的資料表結構設計 適當的冗餘設計 最佳化SQL查詢語句 一張表的欄位不宜過多
10.列舉日常開發中,列舉十個書寫高質量SQL的小技巧
查詢SQL儘量不要使用select *,而是select具體欄位。 小表驅動大表 最佳化你的like語句 儘量避免在索引列上使用mysql的內建函式 如果插入資料過多,考慮批次操作。 多用limit 小表驅動大表 exist & in合理利用 in元素不要過多 儘量用union all替換union
大家可以參考我之前這篇文章哈 :後端程式設計師必備:書寫高質量SQL的30條建議
11.index merge瞭解過嘛?
index merge
是什麼?
在
MySQL
中,當執行一個查詢語句需要使用多個索引時,MySQL可以使用索引合併(Index Merge
)來最佳化查詢效能。具體來說,索引合併是將多個單列索引或多個聯合索引合併使用,以滿足查詢語句的需要。
當使用索引合併時,MySQL
會選擇最優的索引組合來執行查詢,從而避免了全表掃描和排序操作,提高了查詢效率。而對於使用多個單列索引的查詢語句,MySQL也可以使用索引合併來最佳化查詢效能。
大家可以看一個使用index merge
的例子:
假設有一個名為orders
的表,包含order_id、customer_id、product_id、order_date等欄位,其中order_id、customer_id、product_id
三個欄位都建有索引。
如果要查詢customer_id
為1
,order_date
在2022年1月1日到2022年2月1日之間的訂單記錄,可以使用以下SQL語句:
SELECT *
FROM orders
WHERE customer_id = 1
AND order_date >= '2022-01-01'
AND order_date < '2022-02-01'
在執行該查詢語句時,MySQL可以使用customer_id
索引和order_date
索引來最佳化查詢。如果使用單個索引,則需要掃描整個索引樹來匹配查詢條件;但如果使用索引合併,則可以先使用customer_id
索引來過濾出符合條件的記錄,然後再使用order_date
索引來進一步過濾記錄,從而大大減少了掃描的記錄數,提高了查詢效率。
大家可以使用EXPLAIN關鍵字可以檢視查詢計劃,確認是否使用了索引合併。例如,執行以下語句:
EXPLAIN SELECT *
FROM orders
WHERE customer_id = 1
AND order_date >= '2022-01-01'
AND order_date < '2022-02-01'
如果查詢計劃中出現了Using index merge
的資訊,則表示該查詢使用了索引合併最佳化。
12. order by查詢效率慢,如何最佳化.
大家是否還記得order by
查詢為什麼會慢嘛?
order by
排序,分為全欄位排序和rowid
排序。它是拿max_length_for_sort_data
和結果行資料長度對比,如果結果行資料長度超過max_length_for_sort_data
這個值,就會走rowid
排序,相反,則走全欄位排序。
rowid
排序,一般需要回表去找滿足條件的資料,所以效率會慢一點.如果是order by
排序,可能會藉助磁碟檔案排序的話,效率就更慢一點.
如何最佳化order by
的檔案排序?
因為資料是無序的,所以就需要排序。如果資料本身是有序的,那就不會再用到檔案排序啦。而索引資料本身是有序的,我們透過建立索引來最佳化 order by
語句。我們還可以透過調整 max_length_for_sort_data、sort_buffer_size
等引數最佳化;
大家忘記order by
的話,可以看我之前的這篇文章哈:看一遍就理解:order by詳解
13. group by 查詢慢的話,如何最佳化呀.
group by
一般用於分組統計,它表達的邏輯就是根據一定的規則,進行分組。日常開發中,我們使用得比較頻繁。如果不注意,很容易產生慢SQL
。
group by
可能會慢在哪裡?因為它既用到臨時表,又預設用到排序。有時候還可能用到磁碟臨時表。
如果執行過程中,會發現記憶體臨時表大小到達了上限(控制這個上限的引數就是 tmp_table_size
),會把記憶體臨時錶轉成磁碟臨時表。如果資料量很大,很可能這個查詢需要的磁碟臨時表,就會佔用大量的磁碟空間。
如何最佳化group by呢?
group by 後面的欄位加索引 order by null 不用排序 儘量只使用記憶體臨時表 使用SQL_BIG_RESULT
來自 “ ITPUB部落格 ” ,連結:https://blog.itpub.net/70027826/viewspace-3001514/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Oracle 調優確定存在問題的SQLOracleSQL
- MySQL調優篇 | SQL調優實戰(5)MySql
- SQL Server一次SQL調優案例SQLServer
- Oracle SQL調優系列之SQL Monitor ReportOracleSQL
- 效能調優——SQL最佳化SQL
- Oracle 效能調優工具:SQL MonitorOracleSQL
- SQL 調優一般思路SQL
- 記一次SQL Server刪除SQL調優SQLServer
- MySQL 索引和 SQL 調優總結MySql索引
- Oracle SQL調優之分割槽表OracleSQL
- 記一次SQL調優過程SQL
- 大廠都是怎麼SQL調優的?SQL
- mysql調優從書寫sql開始MySql
- 單機百萬連線調優和Netty應用級別調優Netty
- Oracle 高效能SQL引擎剖析--SQL優化與調優機制詳解OracleSQL優化
- 瞭解GaussDB效能調優之隱式轉換,解決慢SQL問題SQL
- 資料庫SQL調優的幾種方式資料庫SQL
- 如何調優 Oracle SQL系列文章:查詢優化器介紹OracleSQL優化
- TiDB SQL調優案例之避免TiFlash幫倒忙TiDBSQL
- 大廠是怎麼進行SQL調優的?SQL
- 【SQL】13 SQL 別名、SQL 連線(JOIN)、SQL INNER JOIN 關鍵字、SQL LEFT JOIN 關鍵字、SQL RIGHT JOIN 關鍵字、SQL FULL OUTER JSQL
- sql優化 面試必問【簡答】SQL優化面試
- [20181119]使用sql profile優化問題.txtSQL優化
- Hive-常見調優方式 && 兩個面試sqlHive面試SQL
- Redis 6.0 新特性-多執行緒連環13問!Redis執行緒
- SQL優化案例-從執行計劃定位SQL問題(三)SQL優化
- 微課sql最佳化(13)、表的連線方法(2)-基礎概念SQL
- PostgreSQL技術大講堂 - 第31講:SQL調優技巧SQL
- 一次SQL調優 聊一聊 SQLSERVER 資料頁SQLServer
- SQL調優工具包DBMS_SQLTUNE的使用方法SQL
- 《我想進大廠》之mysql奪命連環13問MySql
- Spark 效能調優--資源調優Spark
- Spark效能調優-RDD運算元調優篇(深度好文,面試常問,建議收藏)Spark面試
- SQL連線查詢優化[姊妹篇.第五彈]SQL優化
- 調優 | Apache Hudi應用調優指南Apache
- MySQL調優篇 | 表連線方式及演算法(3)MySql演算法
- 面試官問我MySQL調優,我真的是面試MySql
- 阿里面試100%問到,JVM效能調優篇阿里面試JVM