天天看點

mysql 執行sql檔案_Mysql中sql執行如此慢

我們經常發現,往往執行一條簡單的查詢語句,但是很長時間都沒有傳回,今天我們看看是什麼原因導緻的 第一類:查詢長時間不能傳回 執行下面語句

select  *  from  t where id =1;
           

等待MDL鎖 我們按照下面操作,看看會發生什麼呢

mysql 執行sql檔案_Mysql中sql執行如此慢

我們發現sql語句很長時間都不見傳回響應,我們先看一下他的狀态,發現果然是被鎖住了.

mysql 執行sql檔案_Mysql中sql執行如此慢

此類問題我們直接可以找到誰持有MDL的寫鎖,直接kill. 可以用查詢sys.schema_table_lock_waits這張表,我們就可以直接找到阻塞的process id ,把這個連接配接用kill指令斷開即可(mysql啟動的時候設定performation_schema=on)

mysql 執行sql檔案_Mysql中sql執行如此慢

        等待flush

下面我們說另外一種查詢被阻塞的情況,當一個線程正好對表進行flush操作,本身這個線程執行的很快,但是如果這個線程flush線程被其他線程阻塞,最終會導緻阻塞表t的查詢,如下圖所示

mysql 執行sql檔案_Mysql中sql執行如此慢

sessionA中,我們故意調用一次sleep(1),預設執行10萬秒,這個時候t表是打開的,使用flush去關閉表t,就必須等待sessionA結束,同時也會阻塞sessionC

mysql 執行sql檔案_Mysql中sql執行如此慢

等待行鎖 首先,我們看看下面sql語句

mysql> select * from t where id=1 lock in share mode; 
           

要執行上面語句的時候,這個記錄就會要加讀鎖,如果這個時候已經有一個事物在這行記錄上持有一個寫鎖,我們select 語句就會被阻塞。

mysql 執行sql檔案_Mysql中sql執行如此慢
mysql 執行sql檔案_Mysql中sql執行如此慢

這個問題并并不難分析,問題是如何查出誰占着這個寫鎖,如果你用的mysql5.7,可以使用下面語句

mysql> select * from t sys.innodb_lock_waits where locked_table=`'test'.'t'`\G
           
mysql 執行sql檔案_Mysql中sql執行如此慢

可以看到4号線程就是阻塞的罪魁禍首,是以隻要幹掉他就可以了, 不過,這裡不應該顯示kill  query 4,這個指令是指把正在執行的語句停止,但是我們的update語句已經執行完成了,這樣是無法去掉id=1的行鎖. 實際上,kill 4才有效,也就是直接斷開這個連接配接,這裡連接配接被斷開的時候,會自動復原這個連接配接裡面正在執行的線程,也就是釋放id=1上的行鎖.

第二類:查詢慢

我們執行下面語句

select *  from t where c=50000 limit 1;
           

有字段c沒有索引,這個語句隻能全表掃描,是以要掃描5萬行,再看看慢日志的記錄.

mysql 執行sql檔案_Mysql中sql執行如此慢

發現掃描了50000行,消耗時間13.5毫秒,看起來很快,但是目前資料的資料隻有10萬行資料,如果資料量到千萬級别,這個sql就會消耗很多時間。 我們在看看另外sql,如下圖

select *  from t where id=1select *  from t where id=1 lock in share mode
           
mysql 執行sql檔案_Mysql中sql執行如此慢

按照上面操作我們再看看對應的慢查詢日志

mysql 執行sql檔案_Mysql中sql執行如此慢
mysql 執行sql檔案_Mysql中sql執行如此慢

我們發現lock in share mode加鎖操作居然時間比沒有加鎖的查詢塊了,超出了我們的預期,我們再看看每個sql查詢結果

mysql 執行sql檔案_Mysql中sql執行如此慢

此時我們就知道原因了,是因為session A先用start transaction with consistent snapshot啟動了一個事物,然後sessionB才進行更新語句,然後在執行完100萬次update語句後,此時的id是處于下圖的狀态

mysql 執行sql檔案_Mysql中sql執行如此慢

發現session B生産100萬復原日志(undo log),此時lock in share mode的sql語句,是目前讀,是以會直接讀到100001,速度很快,但是select *  from t where id=1,是一緻性讀,是以從1000001開始,依次執行undo log,執行100萬次,才會把1傳回.

如果對您有一絲絲幫助,麻煩點個關注,也歡迎轉發,謝謝

掃碼關注

mysql 執行sql檔案_Mysql中sql執行如此慢