程式面試考題:一條sql執行慢的原因?如何優化?

前文

眾所周知,想要進大廠,MYSQL是必問的技術之一。如果你在中小公司工作,也許對數據庫的操作僅僅簡單CRUD就夠用啦。但是,對於大廠,面對百萬級數據量,如何保證MYSQL性能依舊很好呢?

這其實涉及很多方面:索引、主從讀寫分離、集群、分庫分錶、sql、鎖、參數調優、表結構等。而本文想帶領大家探討一下“

由於筆者水平有限,可能考慮的不是很全面。歡迎留言補充。

關注我的小伙伴應該都知道我的原則:如果想要詳細了解或則想知道它具體內部咋實現的建議仔細去看書,這裡我就簡單分享我的理解,知道這些,面試基本夠用啦。

(悄悄說:

sql怎麼會變慢呢?

我從來不喜歡說廢話、打廣告,網上千篇一律的文章講了半天也get不到點。只為對標大廠面試,接下來看看我怎樣回答吧。乾貨慢慢,若有不足,歡迎留言改正。

我認為,一個SQL 執行的很慢,我們要分兩種情況討論:

1、大多數情況下很正常,偶爾很慢,則有如下原因

(1)、數據庫在
(2)、執行的時候,
(3)、

2、這條SQL 語句一直執行的很慢,則有如下原因
(1)、沒有用上索引或則索引失效:例如該字段沒有索引;或則由於對字段進行運算、函數操作導致無法用索引。
(2)、有索引可能會走全表掃描

怎樣判斷是否走全表掃描:
索引區分度(索引的值不同越多,區分度越高),稱為基數,而數據量大時不可能全部掃描一遍得到基數,而是採樣部分數據進行預測,那有可能預測錯了,導致走全表掃描。

慢sql優化

數據庫中設置SQL慢查詢

方式一:修改配置文件在my.ini 增加幾行: 主要是慢查詢的定義時間(超過2秒就是慢查詢),以及慢查詢log日誌記錄( slow_query_log)

[mysqlld] ```text
[mysqlld] //定义查过多少秒的查询算是慢查询,我这里定义的是2秒long_query_time=2 #5.8、5.1等版本配置如下选项log-slow-queries=mysql_slow_query.log #5.5及以上版本配置如下选项slow-query-log=On slow_query_log_file=mysql_slow_query. log //记录下没有使用索引的query log-query-not-using-indexestpspb16glos dndnorte/t
`` //定義查過多少秒的查詢算是慢查詢,我這裡定義的是2秒long_query_time=2 ``text
[mysqlld] //定义查过多少秒的查询算是慢查询,我这里定义的是2秒long_query_time=2 #5.8、5.1等版本配置如下选项log-slow-queries=mysql_slow_query.log #5.5及以上版本配置如下选项slow-query-log=On slow_query_log_file=mysql_slow_query. log //记录下没有使用索引的query log-query-not-using-indexestpspb16glos dndnorte/t
`` #5.8、5.1等版本配置如下選項log-slow-queries=mysql_slow_query.log ``text
[mysqlld] //定义查过多少秒的查询算是慢查询,我这里定义的是2秒long_query_time=2 #5.8、5.1等版本配置如下选项log-slow-queries=mysql_slow_query.log #5.5及以上版本配置如下选项slow-query-log=On slow_query_log_file=mysql_slow_query. log //记录下没有使用索引的query log-query-not-using-indexestpspb16glos dndnorte/t
`` #5.5及以上版本配置如下選項slow-query-log=On ``text
[mysqlld] //定义查过多少秒的查询算是慢查询,我这里定义的是2秒long_query_time=2 #5.8、5.1等版本配置如下选项log-slow-queries=mysql_slow_query.log #5.5及以上版本配置如下选项slow-query-log=On slow_query_log_file=mysql_slow_query. log //记录下没有使用索引的query log-query-not-using-indexestpspb16glos dndnorte/t
`` slow_query_log_file=mysql_slow_query. log ``text
[mysqlld] //定义查过多少秒的查询算是慢查询,我这里定义的是2秒long_query_time=2 #5.8、5.1等版本配置如下选项log-slow-queries=mysql_slow_query.log #5.5及以上版本配置如下选项slow-query-log=On slow_query_log_file=mysql_slow_query. log //记录下没有使用索引的query log-query-not-using-indexestpspb16glos dndnorte/t
`` //記錄下沒有使用索引的query ``text
[mysqlld] //定义查过多少秒的查询算是慢查询,我这里定义的是2秒long_query_time=2 #5.8、5.1等版本配置如下选项log-slow-queries=mysql_slow_query.log #5.5及以上版本配置如下选项slow-query-log=On slow_query_log_file=mysql_slow_query. log //记录下没有使用索引的query log-query-not-using-indexestpspb16glos dndnorte/t

```

方式二:通過MySQL數據庫開啟慢查詢:

mysql>set global slow_query_log=ON ```text
mysql>set global slow_query_log=ON mysql>set global long_query_time = 3600; mysql>set global log_querise_not_using_indexes=ON;
`` mysql>set global long_query_time = 3600; ``text
mysql>set global slow_query_log=ON mysql>set global long_query_time = 3600; mysql>set global log_querise_not_using_indexes=ON;


### 分析慢查詢日誌

# 可以通過如下命令定位低效率執行sql
 show processlist;
 # sql 可以用

對於執行計劃的分析,也是面試官喜歡考察的一個點。

面試官對於執行計劃你是怎樣分析的?

這裡簡單帶過,之後會詳細解答。主要關注這幾個字段即可:

type

- type=ALL,全表掃描,MySQL遍歷全表來找到匹配行
- type=index,索引全掃描
- type=range,索引範圍掃描
- type=eq_ref,唯一索引
- type=NULL,MySQL不用訪問表或者索引,直接就能夠得到結果(性能最好)

possible_keys
 key
 key_len
 rows
 Extra

- using index:覆蓋索引,不回表
- using where:回表查詢
- using filesort:需要額外的排序,不能通過索引得到排序結果

### 慢sql如何優化

對於MYSQL慢sql語句的優化,我們也可以分幾個方面來進行分析(基本覆蓋全面啦):
面試從這幾方面考慮:索引+sql語句+數據庫結構優化+優化器優化+架構優化。

索引

1、盡量覆蓋索引,5.6支持索引下推
2、組合索引符合最左匹配原則
3、避免索引失效
4、再寫多讀少的場景下,可以選擇普通索引而不要唯一索引更新時,
 5、索引建立原則(一般建在where和order by,基數要大,區分度要高,不要過度索引,外鍵建索引)

sql語句

1、分頁查詢優化該方案適用於主鍵自增的表,可以把Limit查詢轉換成某個位置的查詢。
 select * from tb_sku where id>20000 limit 10;

2、優化insert語句

- 多條插入語句寫成一條
- 在事務中插數據
- 數據有序插入(主鍵索引)

數據庫結構優化

1、將字段多的表分解成多個表有些字段使用頻率高,有些低,數據量大時,會由於使用頻率低的存在而變慢,可以考慮分開。
 2、對於經常聯合查詢的表,可以考慮建立中間表

優化器優化

1、優化器使用MRR
原理:

 mysql
 explain 查看Extra多了一個MRR
 explain select * from

對於Myisam,在去磁盤獲取完整數據之前,會先按照rowid 排好序,再去順序的讀取磁盤。
對於Innodb,則會按照聚簇索引鍵值排好序,再順序的讀取聚簇索引。

磁盤預讀:
索引本身就是為了減少磁盤IO,加快查詢,而MRR,則是把索引減少磁盤IO 的作用,進一步放大
https://

架構優化

總結:
 1、先設置慢查詢(my.ini或數據庫命令)
 2、分析慢查詢日誌
3、定位低效率sql(show processlist)
 4、explain分析執行計劃(是否索引失效,用到索引沒,用了哪些)
 5、優化(索引+sql語句+數據庫結構優化+優化器優化+架構優化)

每日一句:
認識到一個人的靈魂是無法把握的,這是智慧的最終成就。人本身就是最終的謎。 ——by 王爾德

關注我公眾號“

後續會陸續更新大廠面經面試題與解析,大廠內推加油噢!

往期回顧:
 1、我的秋招| 大廠上岸經驗一(末流二本)
 2、阿里面試官:MYSQL是如何實現ACID的?
 3、Mysql架構&事務原理與鎖機制&MVCC日誌(undo log redolog binlog)兩階段提交&組提交

What do you think?

Written by marketer

基於Notion 的筆記寫作和博客分享自動化方案

React Fiber 簡介—— React 背後的算法