MySQL 效能 大字段造成的統計卡頓

2021-10-03 04:02:02 字數 2098 閱讀 8781

建立三張**,test,test1,test2,每張表插入十萬行資料,這三張表的schema都如圖1所示,不同的是每張表的des欄位的長度不同(但同一張**內,每一行des欄位的長度都是相同的),如圖2所示。

重啟測試機,兩次執行sql查詢語句以統計每張表cnt欄位的累加和,並獲取耗時如圖3、4所示

對比圖3和圖4,會發現圖3的查詢時間遠大於圖4查詢的時間,這是因為執行第一次統計的時候,三張表的資料都只存在磁碟裡面,mysql統計的時候,需要將三張表的資料先從磁碟裡面讀到記憶體資料頁裡面,然後才能進行統計操作,這發生了大量的隨機io讀,從而導致統計緩慢。而執行完第一次統計之後,磁碟裡面的資料都被讀到記憶體頁裡面了,因此執行第二次統計的時候就無需再讀磁碟,直接統計記憶體頁裡面的資料即可,避免了隨機讀操作,所以第二次統計速度遠大於第一次統計速度。

我們再看圖3,對比test1和test2**的統計速度,發現test2的統計時間遠遠大於test1的統計時間,這是為什麼?我們回到圖2,發現test2的des欄位的長度(7168)遠大於test1的des字段長度(0),是了沒錯,這就是造成test2比test1慢的原因,我們知道,如果mysql要讀取欄位cnt的值的話,它需要讓innodb把一整行資料都讀入到記憶體當中,然後才能去讀cnt的值,所以如果一行資料過長的話,那麼需要從磁碟中讀取的資料量就多了,特別是執行統計類的操作,隨機讀io會大大增加,這就造成了圖3中test1與test2對比的情況。

說到這裡,細心的讀者可能發現,不對啊,表test的des欄位可是要比表test2的des欄位大多了,那為啥圖3中test的統計時間卻比test2的小那麼多。要解釋這個問題,就不得不提innodb的行溢位的概念了,我們知道innodb是以頁為單位來儲存資料的(乙個頁裡有多行資料),頁的大小為16kb,也就是16384個位元組,而我們的**test光是des欄位就有32768個位元組,顯然這一行資料就已經超過了乙個頁的大小,造成了行溢位。一般情況下,innodb都是將資料存放在b-tree node的頁型別當中,也就是那個16kb的頁,但是發生了行溢位時,innodb會將溢位的行分為兩部分,一部分放在b-tree node的頁型別中,另一部分放在uncompress blob頁中,如圖5所示,b-tree node頁中存放著前768個位元組的字首資料,之後跟的偏移量,指向uncompress blob頁。所以我們的test表的innodb行中其實只存放了字段des的字首和相應的偏移量,一共幾百位元組,比test2要小的多,那test的統計時間自然是要小於test2的。

如果對行溢位感興趣的讀者可以翻閱《mysql技術內幕 innodb儲存引擎 第2版》一書,這裡就不贅述了。

我們再看看有沒有方法能夠優化表test2的查詢速度,答案是有的,我們知道,innodb是以b+樹的方式來組織索引結構的[1],其中主鍵索引樹的葉子節點存的是整行資料,非主鍵索引樹的葉子節點存的是主鍵的值,我們當前的統計之所以這麼慢是因為我們從主鍵索引樹的葉子節點中讀了整行資料,倘若我們能夠為字段cnt建立索引,那麼我們統計的時候就無需去遍歷主鍵索引樹了,直接遍歷非主鍵索引樹即可,就避免了讀整行資料,減小了隨機讀io。

執行語句

alter table test2 create index ix_cnt(`cnt`) using btree;
重啟測試機後查詢時長如圖6所示

[1](極客時間)深入淺出索引(上).

mysql 寫binlog 大字段流程

當寫binlog大於8192既io cache 的大小時,不寫io cache 直接寫入檔案pagecache 當io cache 剩餘空間無法寫入當前binlog時,則先把io cache 裡的內容寫入直接寫入檔案pagecache 0 my b write info 0x2d9b248 840 ...

mysql 讀效能統計 MySQL的效能分析

1.mysql query optimizer mysql服務層自帶的優化器 1 mysql中有專門負責優化select語句的優化器模組,主要功能 通過計算分析系統中收集到的統計資訊,為客戶端 請求的query提供他認為最優的執行計畫 他認為最優的資料檢索方式,但不見得是dba認為最優的,這部分最耗...

db2的大字段CLOB,BLOB,DBCLOB

db2有三種型別的大字段 clob character large objects 適用於存放單位元組的字串,當我們要儲存的字元長度超過varchar的最大長度 32k 時,我們就要考慮使用clob了。dbclob double byte character large objects dbclob...