資料庫專題 深入理解count 為什麼這麼慢

2021-10-09 08:58:05 字數 1935 閱讀 2086

曾經在依次面試中被問到過這麼乙個問題,假設開發乙個交易平台過程中,有遇到過需要計算交易記錄總數的情況該怎麼辦。可能大多數人的回答都是用select count(*) from t 不就搞定了嗎 但是,面試官又問到隨著系統中記錄數越來越多,這條語句執行得越來越慢。那麼為什麼這麼慢呢,今天我們就來聊一聊原因吧。

mysql在不同的儲存引擎中,count(*)的實現方式也不相同。

一般來說myisam引擎效率比較高,因為它是把乙個表的總行數存到了磁碟上,因此執行count(*)的時候回直接返回計數值。但是如果加上where的話,myisam的表也不能反應這麼快。

innodb引擎它執行count(*)的時候比較麻煩,它需要把資料一行一行地從引擎裡面讀出來,然後再進行累計計數。

即使同一時刻的多個查詢,由於多版本併發控制(mvcc)的原因,事務t啟動的時候會建立乙個檢視read-view,innodb的表根據檢視進行計數的。因此不能確定應該返回多少行。下面我們舉個例子來解釋一下:

假設表t1有5000條記錄,三個使用者並行的會話。

會話1會話2會話3

begin;

select count(*) from t1;

insert into t1 ()

begin;

insert into t1 ()

select count(*) from t1(返回5000)

select count(*) from t1(返回5002)

select count(*) from t1(返回5001)

最後,三個會話會同時查詢表t1的總行數,但拿到的結果卻不相同。這個原因其實和事務的設計有一定關係。一般預設隔離級別是可重複讀(repatable-read)

而可重複讀是通過mvcc來實現。每一行記錄都要判斷是否對這個會話可見。因此就count(*)來說,innodb只好把資料逐行地讀出並判斷,只有可見的行才能被用來計算表的總行數。

mysql實際上是做了優化的,innodb是索引組織表,主鍵索引樹的葉子節點是資料,而普通索引樹的葉子節點是主鍵值。因此普通索引樹比主鍵索引樹小很多。對於count(*)操作遍歷哪棵樹邏輯上來講結果都是一樣的。因此,為了遵循減少資料量遍歷的原則,mysql的優化器會找到最小的那顆樹來進行遍歷。

這裡提到的主鍵索引樹和普通索引樹是什麼意思?我們來舉個例子:

假設有張innodb表t (id pk, name key, ***, flag)

表中有四條記錄:

1, song, m, a

3, zhang, m, a

5, li, m, a

9, wang, f, b

則它們的索引樹如下圖所示:

假設要執行語句select * from t where name=』song』;

(1)首先在name普通索引上查詢到pk=1;

(2)再在主鍵索引樹上查詢到(1,song, m, a)的行記錄;

其實mysql有條命令show tables status命令執行結果中有條rows能用於顯示表有多少行,比如我們有張表結構是這樣的

插入資料後,執行show table status命令結果如下:

這條命令執行比count(* )快,那用它來代替count(*)豈不是很快。但是不行,為什麼呢?

它不夠準確,因為它的值是根據mysql取樣統計估算出來的,官方統計,誤差還是可能會達到40%-50%。

深入理解資料庫鎖

oracle中分為兩種模式的鎖,一種是排他鎖 x鎖 另一種是共享所 s鎖 鎖是實現併發的主要手段,在資料庫中應用頻繁,但很多都由資料庫自動管理,當事務提交後會自動釋放鎖.oracle為了使資料庫實現高度併發訪問,它使用了不同型別的鎖來管理併發會話對資料物件的操作.oracle的鎖按作用物件不同分為如...

深入理解資料庫併發控制原理

併發控制原理 事務之間的相互影響可能導致資料庫狀態的不一致,即使各個事務能保持狀態的正確性,而且也沒有任何故障發生。因此,不同事務中各個步驟的執行順序必須以某種方式進行規範。控制這些步驟的功能由dbms的排程器部件完成,而保證併發執行的事務能保持一致性的整個過程稱為併發控制。排程器的作用如圖1所示。...

mysql深入理解資料庫索引結構

1 資料庫檔案儲存的方式 資料庫檔案儲存都是以磁碟檔案儲存在系統中的,這也是資料庫能持久化儲存資料的原因。2 從資料庫讀取資料的原理 從資料庫讀取資料,先暫且不考慮從快取中讀取資料的情況,那就是從磁碟檔案中讀取資料的,我們知道從磁碟檔案中讀取資料是比較耗時的,資料庫的select操作的時間,取決於執...