MySQL實戰45講 19

来源:https://www.cnblogs.com/ydssx7/archive/2022/07/28/16530137.html
-Advertisement-
Play Games

19 | 為什麼我只查一行的語句,也執行這麼慢? 有些情況下,“查一行”,也會執行得特別慢。 需要說明的是,如果 MySQL 資料庫本身就有很大的壓力,導致資料庫伺服器 CPU 占用率很高或 ioutil(IO 利用率)很高,這種情況下所有語句的執行都有可能變慢,不屬於本章討論範圍。 為了便於描述, ...


19 | 為什麼我只查一行的語句,也執行這麼慢?

有些情況下,“查一行”,也會執行得特別慢。

需要說明的是,如果 MySQL 資料庫本身就有很大的壓力,導致資料庫伺服器 CPU 占用率很高或 ioutil(IO 利用率)很高,這種情況下所有語句的執行都有可能變慢,不屬於本章討論範圍。

為了便於描述,構造一個表,基於這個表來說明問題。這個表有兩個欄位 id 和 c,並且在裡面插入了 10 萬行記錄。

CREATE TABLE `t` (
  `id` int(11) NOT NULL,
  `c` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;
 
delimiter ;;
create procedure idata()
begin
  declare i int;
  set i=1;
  while(i<=100000)do
    insert into t values(i,i);
    set i=i+1;
  end while;
end;;
delimiter ;
 
call idata();

第一類:查詢長時間不返回

在表 t 執行下麵的 SQL 語句:

select * from t where id=1;

查詢結果長時間不返回。

image-20220728170411761

一般碰到這種情況的話,大概率是表 t 被鎖住了。接下來分析原因的時候,一般都是首先執行一下 show processlist 命令,看看當前語句處於什麼狀態。

然後再針對每種狀態,去分析它們產生的原因、如何復現,以及如何處理。

等 MDL 鎖

下圖就是使用 show processlist 命令查看 Waiting for table metadata lock 的示意圖。

出現這個狀態表示的是,現在有一個線程正在表 t 上請求或者持有 MDL 寫鎖,把 select 語句堵住了。

復現這個場景

session A 通過 lock table 命令持有表 t 的 MDL 寫鎖,而 session B 的查詢需要獲取 MDL 讀鎖所以,session B 進入等待狀態

這類問題的處理方式,就是找到誰持有 MDL 寫鎖,然後把它 kill 掉。

但是,由於在 show processlist 的結果裡面,session A 的 Command 列是“Sleep”,導致查找起來很不方便。不過有了 performance_schema 和 sys 系統庫以後,就方便多了。(MySQL 啟動時需要設置 performance_schema=on,相比於設置為 off 會有 10% 左右的性能損失)

通過查詢 sys.schema_table_lock_waits 這張表,我們就可以直接找出造成阻塞的 process id,把這個連接用 kill 命令斷開即可

等 flush

另外一種查詢被堵住的情況

在表 t 上,執行下麵的 SQL 語句:

select * from information_schema.processlist where id=1;

查出來這個線程的狀態是 Waiting for table flush,這個狀態表示的是,現在有一個線程正要對錶 t 做 flush 操作

MySQL 裡面對錶做 flush 操作的用法,一般有以下兩個:

flush tables t with read lock;
 
flush tables with read lock;

這兩個 flush 語句,如果指定表 t 的話,代表的是只關閉表 t;如果沒有指定具體的表名,則表示關閉 MySQL 里所有打開的表。

正常這兩個語句執行起來都很快,除非它們也被別的線程堵住了。

所以,出現 Waiting for table flush 狀態的可能情況是:有一個 flush tables 命令被別的語句堵住了,然後它又堵住了我們的 select 語句。

復現一下這種情況,復現步驟如下圖所示:

在 session A 中,故意每行都調用一次 sleep(1),這樣這個語句預設要執行 10 萬秒,在這期間表 t 一直是被 session A“打開”著。然後,session B 的 flush tables t 命令再要去關閉表 t,就需要等 session A 的查詢結束。這樣,session C 要再次查詢的話,就會被 flush 命令堵住了。

等行鎖

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

由於訪問 id=1 這個記錄時要加讀鎖,如果這時候已經有一個事務在這行記錄上持有一個寫鎖, select 語句就會被堵住。

行鎖復現步驟和現場如下:

行鎖 show processlist 現場如下圖:

顯然,session A 啟動了事務,占有寫鎖,還不提交,是導致 session B 被堵住的原因。

這個問題並不難分析,但問題是怎麽查出是誰占著這個寫鎖。???(待解決)

mysql 查看誰在持有鎖

show engine innodb status查看,但是它只顯示誰在等待鎖,無法查看到誰持有鎖;

第二類:查詢慢

掃描行數多,所以執行慢

select * from t where c=50000 limit 1;

由於欄位 c 上沒有索引,這個語句只能走 id 主鍵順序掃描,因此需要掃描 5 萬行。

作為確認,可以看一下慢查詢日誌。這裡為了把所有語句記錄到 slow log 里,在連接後先執行了 set long_query_time=0將慢查詢日誌的時間閾值設置為 0

下圖為全表掃描 5 萬行的 slow log

Rows_examined 顯示掃描了 50000 行。不是很慢呀,11.5 毫秒,線上一般都配置超過 1 秒才算慢查詢。但要記住:壞查詢不一定是慢查詢。這個例子裡面只有 10 萬行記錄,數據量大起來的話,執行時間就線性漲上去了。

掃描一行卻執行得很慢

select * from t where id=1;

雖然掃描行數是 1,但執行時間卻長達 800 毫秒。

下一個語句

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

執行時掃描行數也是 1 行,執行時間是 0.2 毫秒

Q:按理說 lock in share mode 還要加鎖,時間應該更長才對,為什麼?

A:

下圖是這兩個語句的執行輸出結果。

第一個語句的查詢結果里 c=1,帶 lock in share mode 的語句返回的是 c=1000001。

復現步驟

session A 先用 start transaction with consistent snapshot 命令啟動了一個事務,之後 session B 才開始執行 update 語句。

session B 執行完 100 萬次 update 語句後id狀態如下:

session B 更新完 100 萬次,生成了 100 萬個回滾日誌 (undo log)。

帶 lock in share mode 的 SQL 語句,是當前讀,因此會直接讀到 1000001 這個結果,所以速度很快;而 select * from t where id=1 這個語句,是一致性讀因此需要從 1000001 開始,依次執行 undo log,執行了 100 萬次以後,才將 1 這個結果返回。

PS:undo log 里記錄的其實是“把 2 改成 1”,“把 3 改成 2”這樣的操作邏輯,畫成減 1 的目的是方便看圖。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • GraphPad Prism 9 for Mac是一款專業的科研統計分析繪圖軟體,世界領先的科學家都在使用Prism 9 Mac,使用Prism 9 Mac版幫助您有效的分析、統計並繪製出直觀的圖形,幫您節省大量的時間,讓您更加專註於您的科研。 詳情:GraphPad Prism 9 for Mac ...
  • 前言 製作centos7無人值守安裝,在windows下也可以進行,但是由於U盤文件系統的問題,難免需要在windows和centos7下來回切換,進行配置,才能完成製作,比如主分區exfat格式用於存放ISO和ks.cfg文件通常情況下只能被windows讀取,centos7下讀取不到,掛載不上, ...
  • DxO PureRAW Mac版是發佈了,該軟體採用了智能技術,以解決影響所有RAW文件的七個問題:去馬賽克,降噪,波紋,變形,色差,不想要的漸暈,以及缺乏清晰度。 詳情:DxO PureRAW for mac(raw照片處理器) 功能特色 釋放Adobe Photoshop和Lightroom的R ...
  • 想給自己的照片變得高大上嗎?那就來試試這裡的DxO PhotoLab for Mac版raw圖片處理軟體吧。它可以隨時手動調整,控制照片的各個方面。dxo photolab mac版還能去除噪音有效地消除了光的限制,檢索顏色的細節,應用複雜的光學校正和增強細節。 詳情:DxO PhotoLab 5 ...
  • 換源(建議清華源或者阿裡源) sudo apt update sudo apt upgrade # 軟體升級 sudo apt dist-upgrade #內核更新 grub-customizer 引導控制工具 sudo add-apt-repository ppa:danielrichter200 ...
  • 一、電腦基礎和Linux基礎知識 1.馮諾依曼體繫結構 1946年美籍匈牙利數學家馮·諾依曼於提出存儲程式原理,把程式本身當作數據來對待,程式和該程式處理的數據用同樣的方式儲存。馮·諾依曼體系的要點是: 數字電腦的數制採用二進位,bit位, byte位元組1 byte = 8 bit 電腦應該按 ...
  • #資料庫的CRUD語句 ##INSERT語句 ###在指定列中插入數據 INSERT INTO 表名 (column1,column2,column3,...) VALUES (value1,value2,value3,...); INSERT INTO website (url,country) ...
  • 使用flink的時候難免和redis打交道,相信大家都使用過flink-connector-redis來處理,但是當我想要使用RedisSink寫入集群時,發現居然不支持使用密碼,於是有了這篇筆記。 ...
一周排行
    -Advertisement-
    Play Games
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...