㈠ 美團面試題:慢sql有遇到過嗎是怎麼解決的
大家好,我是田維常,可以叫我老田,也可以叫我田哥
。2017年的時候,我剛去上海,朋友內悄指早推我去美團面試,之前我也寫過一個一篇文章,也是在美團面試中遇到的:
美團面試題:String s = new String("111")會創建幾個對象?
關於慢SQL,我和面試官扯了很久,面試官也是很謙虛的,總是點頭,自己以為回答的還可以。最後的最後,還是說了「 你先回去等通知吧! 」。
所以,我決定把這個慢SQL技術點,好好和你分享分享。希望你下次在遇到類似的面試,能順順利利輕輕鬆鬆的斬獲自己想要的offer。
MySQL的慢查詢日誌是MySQL提供的一種日誌記錄,它用來記錄MySQL中查詢時間超過(大於)設置閾值(long_query_time)的語句,記錄到慢查詢日誌中。
其中,long_query_time的默認值是10,單位是秒,也就是說默認情況下,你的SQL查詢時間超過10秒就算慢SQL了。
在MySQL中,慢SQL日誌默認是未開啟的,也就說就算出現了慢SQL,也不會告訴你的,如果需要知道哪些SQL是慢SQL,需要我們手動開啟慢SQL日誌的。
關於慢SQL是否開啟,我們可以通過下面這個命令來查看:
在這里插入圖片描述
通過命令,我們就可以看到slow_query_log項為OFF,說明我們的慢SQL日誌並未開啟。另外我們也可以看到我們慢SQL日誌存放於哪個目錄下和日誌文件名。
下面我們來開啟慢SQL日誌,執行下面的命令:
這里需要注意,這里開啟的是我們當前的資料庫,並且,我們重啟資料庫後會失效的。
開啟慢SQL日誌後,再次查看:
slow_query_log項已經變成ON,說明開啟成功。
上面說過慢SQL默認時間是10秒,我們通過下面的命令就可以看到我們慢SQL的默認時間:
在這里插入圖片描述
我們總不能一直使用這個默認值,可能很多業務需要時間更短或更長,所以此時,我們就需要對默認時間進行修改,修改命令如下:
修改完了,我們再來看看是否已經改成了3秒。
這里需要注意:想要永久的生效,還需要修改MySQL下面的配置文件my.cnf 文件。
注意:不同操作系統,配置有些區別。
Linux操作系統中
Windows操作系統中
執行一條慢SQL,因為我們前面已經設置好了慢SQL時間為3秒,所以,我們只要執行一條SQL時間超過3秒即可。
該SQL耗時4.024秒,下面我們就來查看慢SQL出現了多少條。
使用命令:
找到慢SQL日誌文件,打開後就會出現類似下面這樣的語句;
簡單說明:
切記
通常我們定位慢SQL有兩種方式:
第一種:定位慢查詢 SQL 可以通過兩個表象進行判斷
第二種:根據不同的資料庫使用不同的方式獲取問題 SQL
如果開啟了慢SQL日誌後,可能會有大量的慢SQL日誌產生,此時再用肉眼看,那是不太現實的,所以大佬們就給我搞了個工具: mysqlmpslow 。
mysqlmpslow 能將相同的慢SQL歸類,並統計出相同的SQL執行的次數,每次執行耗時多久、總耗時,每次返回的行數、總行數,以及客戶端連接信息等。
通過命令
可以看到相關參數的說明:
比較常用的參數有這么幾個:
mysqlmpslow 常用的使用逗慶方式如下:
如上一條命令,應該是mysqlmpslow最簡單的一種形式,其中-s參數是以什麼方式排序的意思,c指代的是以總數從大到小的方式排序。-s的常用子參數有:c: 相同查詢以查詢條數和從大到小排序。t: 以查詢總時間的方式從大到小排序。l: 以查詢鎖的總時間的方式從大到小排序。at: 以查詢平均時間的方式從大到小排序。al: 以查詢鎖平均時間的方式從大到啟雀小排序。
同樣的,還可以增加其他參數,實際使用的時候,按照自己的情況來。
其他常用方式:
接下,我們來個實際操作。
這其中的 SQL 語句因為涉及某些信息,所以我都用*號將主體替換了,如果希望得到具體的值,使用-a參數。
使用 mysqlmpslow 查詢出來的摘要信息,包含了這些內容:
Count : 464 :表示慢查詢日誌總共記錄到這條sql語句執行的次數;
Time=18.35s (8515s) :18.35s表示平均執行時間(-s at),8515s表示總的執行時間(-s t);
Lock=0.01s (3s) :與上面的Time相同,第一個表示平均鎖定時間(-s al),括弧內的表示總的鎖定時間(-s l)(也有另一種說法,說是表示的等待鎖釋放的時間);
Rows=90884.0 (42170176) : 第一個值表示掃描的平均行數(-s ar),括弧內的值表示掃描的總行數(-s r)。
是不是
so easy!!!!
㈡ 如何解決SQL查詢速度太慢
1. 執行計劃中明明有使用到索引,為什麼執行還是這么慢?
2. 執行計劃中顯示掃描行數為 644,為什麼 slow log 中顯示 100 多萬行?
a. 我們先看執行計劃,選擇的索引 「INDX_BIOM_ELOCK_TASK3(TASK_ID)」。結合 sql 來看,因為有 "ORDER BY TASK_ID DESC" 子句,排序通常很慢,如果使用了文件排序性能會更差,優化器選擇這個索引避免了排序。
那為什麼不選 possible_keys:INDX_BIOM_ELOCK_TASK 呢?原因也很簡單,TASK_DATE 欄位區分度太低了,走這個索引需要掃描的行數很大,而且還要進行額外的排序,優化器綜合判斷代價更大,所以就不選這個索引了。不過如果我們強制選擇這個索引(用 force index 語法),會看到 SQL 執行速度更快少於 10s,那是因為優化器基於代價的原則並不等價於執行速度的快慢;
b. 再看執行計劃中的 type:index,"index" 代表 「全索引掃描」,其實和全表掃描差不多,只是掃描的時候是按照索引次序進行而不是行,主要優點就是避免了排序,但是開銷仍然非常大。
Extra:Using where 也意味著掃描完索引後還需要回表進行篩選。一般來說,得保證 type 至少達到 range 級別,最好能達到 ref。
在第 2 點中提到的「慢日誌記錄Rows_examined: 1161559,看起來是全表掃描」,這里更正為「全索引掃描」,掃描行數確實等於表的行數;
c. 關於執行計劃中:「rows:644」,其實這個只是估算值,並不準確,我們分析慢 SQL 時判斷准確的掃描行數應該以 slow log 中的 Rows_examined 為准。
4. 優化建議:添加組合索引 IDX_REL_DEVID_TASK_ID(REL_DEVID,TASK_ID)
優化過程:
TASK_DATE 欄位存在索引,但是選擇度很低,優化器不會走這個索引,建議後續可以刪除這個索引:
select count(*),count(distinct TASK_DATE) from T_BIOMA_ELOCK_TASK;+------------+---------------------------+| count(*) | count(distinct TASK_DATE) |+------------+---------------------------+| 1161559 | 223 |+------------+---------------------------+
在這個 sql 中 REL_DEVID 欄位從命名上看選擇度較高,通過下面 sql 來檢驗確實如此:
select count(*),count(distinct REL_DEVID) from T_BIOMA_ELOCK_TASK;+----------+---------------------------+| count(*) | count(distinct REL_DEVID) |+----------+---------------------------+| 1161559 | 62235 |+----------+---------------------------+
由於有排序,所以得把 task_id 也加入到新建的索引中,REL_DEVID,task_id 組合選擇度 100%:
select count(*),count(distinct REL_DEVID,task_id) from T_BIOMA_ELOCK_TASK;+----------+-----------------------------------+| count(*) | count(distinct REL_DEVID,task_id) |+----------+-----------------------------------+| 1161559 | 1161559 |+----------+-----------------------------------+
在測試環境添加 REL_DEVID,TASK_ID 組合索引,測試 sql 性能:alter table T_BIOMA_ELOCK_TASK add index idx_REL_DEVID_TASK_ID(REL_DEVID,TASK_ID);
添加索引後執行計劃:
這里還要注意一點「隱式轉換」:REL_DEVID 欄位數據類型為 varchar,需要在 sql 中加引號:AND T.REL_DEVID = 000000025xxx >> AND T.REL_DEVID = '000000025xxx'
執行時間從 10s+ 降到 毫秒級別:
1 row in set (0.00 sec)
結論
一個典型的 order by 查詢的優化,添加更合適的索引可以避免性能問題:執行計劃使用索引並不意味著就能執行快。
㈢ 大神們幫忙看看這個SQL語句執行有點慢,要怎麼優化才變快點
你好,根據SQL,我給予一些建議,最好根據執行計劃:
若走的全表掃描,建議建立表間關聯欄位索引,查看索引失效原因,修改SQL關聯邏輯,大部分都能解決。
如果是數據量大的問題:
a. 如果有多個查詢條件,建議建立where限制條件,減少數據統計范圍。
b. 如果實時性要求不高,可以定時跑批,把結果放在結果表裡,前台查詢結果表。
c. 關聯表太多,SQL建議拆分兩端,sum統計單獨放一個SQL。
㈣ SQL 語句執行很慢是怎麼回事
到這個數量級的全部更新,肯定會很慢。x0dx0a第一。你的記錄不一定在同一個partition,x0dx0a第二。不明白為什麼那麼多人建議你建索引,你建的索引越多,你的更新速度越慢,因為你更新記錄的同時,還有更新索引。x0dx0a第三。你必須知道更新速度慢的瓶頸在哪裡。是讀寫太多,還是內存不夠,還是CUP不夠快,然後對症下葯。x0dx0ax0dx0a下面介紹兩個簡單的辦法,也許有效:x0dx0a第一:x0dx0a把這個100W行的表縱向劈成兩個,用外鍵關系連接,一個裝小的,經常改變的數據比如ID,外鍵,狀態值,時間等,另一個裝大的,不經常改變的數據,比如很長的字元串,xml,text 等。x0dx0a這樣更新時操作小的這個表,可以大大節約內存和CPU 開銷,降低磁碟操作。x0dx0a壞處就是查詢時會慢些。 x0dx0a第二:x0dx0a把這100W行橫向切成很多個表,比如每個月的記錄裝在一個表裡,這樣每個表的記錄數可能只有幾萬,查詢,更新都會快很多。x0dx0a壞處是查詢,更新都不如原來好寫。
㈤ 為什麼我的SQL資料庫變的很慢
如果開始的時候不是這樣,那應該是數據量過大,你可以考慮備份部分數據,然後再刪掉資料庫中的數據;還有可能就是你電腦軟體裝多了,使電腦變慢了;當然,也很有可能是中毒了,殺殺毒試試
㈥ 如何解決SQL查詢速度太慢
呵呵,這個問題很有趣不是嗎?
上面的同志們只是給出一些建議,以我的經驗來看(oracle),
如果數據量較大,索引的重復量盡量避免,最好的方式是建立非業務id(最好使用自增或是序列),把這個id建立索引。
你的最大的問題就是,建立了索引後,索引列必須出現在where中,否則索引就白白建立了,比如你的id是從1一直到383000,那麼你的語句可以寫成
select
*
from
hr_worktime
where
id>-1
還有就是,where條件中避免出現!=,or,between,等東西,否則索引實效。