1. 程式人生 > >為什麼 select count(*) from t,在 InnoDB 引擎中比 MyISAM 慢?

為什麼 select count(*) from t,在 InnoDB 引擎中比 MyISAM 慢?

統計一張表的總數量,是我們開發中常有的業務需求,通常情況下,我們都是使用 select count(*) from t SQL 語句來完成。隨著業務資料的增加,你會發現這條語句執行的速度越來越慢,為什麼它會變慢呢?

為什麼會變慢?想要得到答案就需要知道 MySQL 是如何統計總數量的,先說一個前提吧,count(*) 的具體實現是由儲存引擎實現的,也就是說不同的儲存引擎實現的方式不一樣。標題:為什麼select count( * ) from t,在 InnoDB 引擎中比 MyISAM 慢?也是高頻面試題。

InnoDB和MyISAM 是我們常用的 MySQL 儲存引擎,所以主要對比一下 count(*)

在 InnoDB 和 MyISAM 中的實現:

  • **在 MyISAM 儲存引擎中,把表的總行數儲存在磁碟上,當執行 select count(*) from t 時,直接返回總資料**。
  • **在 InnoDB 儲存引擎中,跟 MyISAM 不一樣,沒有將總行數儲存在磁碟上,當執行 select count(*) from t 時,會先把資料讀出來,一行一行的累加,最後返回總數量**。

知道了 InnoDB 和 MyISAM 引擎 count(*) 實現之後,為什麼select count(*) from t,在 InnoDB 引擎中比 MyISAM 慢?應該有答案了吧,但是這個結論需要有一個前提,就是統計 SQL 不帶過濾條件。如果 統計數量 SQL 語句為:select count(*) from t where x = 23

,那麼在 MyISAM 中就不一定比 InnoDB 快了。

**InnoDB 中 count(*) 語句是在執行的時候,全表掃描統計總數量,所以當資料越來越大時,語句就越來越耗時了**,為什麼 InnoDB 引擎不像 MyISAM 引擎一樣,將總行數儲存到磁碟上?這跟 InnoDB 的事務特性有關,由於多版本併發控制(MVCC)的原因,InnoDB 表“應該返回多少行”也是不確定的。

不妨用一個例子來說明一下,假設現在 t 表中有 10000 條資料,現在有三個使用者同時訪問的會話:

  • 會話 A 先啟動事務並查詢一次表的總行數。
  • 會話 B 啟動事務,插入一行後記錄後,查詢表的總行數。
  • 會話 C 先啟動一個單獨的語句,插入一行記錄後,查詢表的總行數。

假設從上到下是按照時間順序執行的,同一行語句是在同一時刻執行的。可以看出在最後時刻,三個會話返回的總行數不一樣。

出現不一樣的結果跟 InnoDB 儲存引擎有關係,在預設隔離級別可重複讀的情況下,通過多版本併發控制(MVCC)來實現,每一行記錄都需要判斷自己是否對這個會話可見,因此在統計總數量時,InnoDB 只好把資料一行一行的讀取出來判斷,只有當前會話可見的才納入統計中。所以同一時刻不同會話查詢到的數量就不一樣。

InnoDB 引擎在 count(*)語句上也做了優化,我們知道,在 InnoDB 儲存引擎中是以索引組織表的方式儲存資料,主鍵索引樹上葉子節點存放在所有的資料,而普通索引樹的葉子節點是主鍵值,所以普通索引樹會比主鍵索引樹小很多,但是數量是一樣的,也就是說遍歷主鍵索引樹和普通索引樹得到的結果都是一樣的。MySQL 就利用了這一特性,在 InnoDB 中執行 select count(*) from t 語句時,MySQL 優化器會找到最小的那棵索引樹來遍歷,這樣可能就可以減少載入次數,在一定程度上提升了 count(*)的執行效率。

最後

目前網際網路上很多大佬都有MySQL相關文章,如有雷同,請多多包涵了。原創不易,碼字不易,還希望大家多多支援。若文中有所錯誤之處,還望提出,謝謝。

相關推薦

為什麼 select count(*) from tInnoDB 引擎 MyISAM

統計一張表的總數量,是我們開發中常有的業務需求,通常情況下,我們都是使用 select count(*) from t SQL 語句來完成。隨著業務資料的增加,你會發現這條語句執行的速度越來越慢,為什麼它會變慢呢? 為什麼會變慢?想要得到答案就需要知道 MySQL 是如何統計總數量的,先說一個前提吧,coun

MySQL存儲引擎MyISAMInnoDB區別詳解

訪問 過程 包含 lte 處理機制 comm 用戶 isam log MyISAM是MySQL的默認數據庫引擎(5.5版之前),由早期的ISAM(Indexed Sequential Access Method:有索引的順序訪問方法)所改良。雖然性能極佳,但卻有一個缺點:不

select count(*) from user註入

select from pre rom col 直接 語句 bstr lec 先來看一條sql語句: 1 mysql> select * from flag where id =1; 2 +------+----------+----------+---------

通過非聚集索引讓select count(*) from 的查詢速度提高几十倍、甚至千倍

通過非聚集索引,可以顯著提升count(*)查詢的效能。 有的人可能會說,這個count(*)能用上索引嗎,這個count(*)應該是通過表掃描來一個一個的統計,索引有用嗎? 不錯,一般的查詢,如果用索引查詢,也就是用Index Seek了,查詢就會很快。  

使用JDBC獲取select count(*) from table_name

public int getCount() { int count = 0; PreparedStatement ps = null;         ResultSet rs = null;   &

RestHighLevelClient 實現 select count from table group by filed

String id = null; try {SearchRequest request = new SearchRequest(IndexAndTypeConstant.PROPERTY_SQL); request.types(IndexAndTypeConst

MySQL儲存引擎MyISAMInnoDB區別詳解

在使用MySQL的過程中對MyISAM和InnoDB這兩個概念存在了些疑問,到底兩者引擎有何分別一直是存在我心中的疑問。為了解開這個謎題,搜尋了網路,找到了如下資訊: MyISAM是MySQL的預設資料庫引擎(5.5版之前),由早期的ISAM(Indexed Sequent

mysql資料庫select count() from table、date屬性值相減、SUM()函式返回值型別

1.select  count(*) from tablename ; 用hibernate查詢時,返回給實體類的型別是 BigInteger型別,實體類接受該欄位的屬性要設定為BigInteger型

select count(*) from v$lock 查詢

pre query run against 優化 9.1 sql slow sel select count(*) from v$lock 查詢慢 解決方法,具體原因看官方優化文檔哈 SQL> set time on 00:51:52 SQL> select

通過非聚集索引讓select count(*) from 的查詢速度提高幾十倍、甚至千倍

意思 topic sni article 分析 簡單 主鍵 begin 應該 通過非聚集索引,可以顯著提升count(*)查詢的性能。 有的人可能會說,這個count(*)能用上索引嗎,這個count(*)應該是通過表掃描來一個一個的統計,索引有用嗎? 不錯,一般

不就是SELECT COUNT語句嗎竟然能被面試官虐的體無完膚

資料庫查詢相信很多人都不陌生,所有經常有人調侃程式設計師就是CRUD專員,這所謂的CRUD指的就是資料庫的增刪改查。 在資料庫的增刪改查操作中,使用最頻繁的就是查詢操作。而在所有查詢操作中,統計數量操作更是經常被用到。 關於資料庫中行數統計,無論是MySQL還是Oracle,都有一個函式可以使用,那就是COU

聊一聊 InnoDB 引擎的索引型別

索引對資料庫有多重要,我想大家都已經知道了吧,關於索引可能大家會對它多少有一些誤解,首先索引是一種資料結構,並且索引不是越多越好。合理的索引可以提高儲存引擎對資料的查詢效率。 形象一點來說呢,索引跟書本的目錄一樣,能否快速的查詢到你需要的資訊,取決於你設計的目錄是否合理。 MySQL 資料庫有很多種索引,每種

B-Tree 和 B+Tree 結構及應用InnoDB 引擎 MyISAM 引擎

1.什麼是B-Tree 和 B+Tree,他們是做什麼用的?     B-Tree是為了磁碟或其它儲存裝置而設計的一種多叉平衡查詢樹,B-Tree 和 B+Tree 廣泛應用於檔案儲存系統以及資料庫系統中。     在大規模資料儲存中,實現索引查詢這樣一個

聊一聊 InnoDB 引擎的這些索引策略

在上一篇中,我們簡單的介紹了一下 InnoDB 引擎的索引型別,這一篇我們繼續學習 InnoDB 的索引,聊一聊索引策略,更好的利用好索引,提升資料庫的效能,主要聊一聊覆蓋索引、最左字首原則、索引下推。 覆蓋索引 覆蓋索引是指在普通索引樹中可以得到查詢的結果,不需要在回到主鍵索引樹中再次搜尋。 建立如下這張表

InnoDB引擎從大表刪除多行

int ota man erro delete mysql 最小 following 可能 官方建議: InnoDB Tables If you are deleting many rows from a large table, you may exceed the l

SQLDQL語句:select * from tb_name為什麼不介意使用而建議使用select 欄位1欄位2...欄位n from tb_name

  首先,其實select 欄位1,欄位2...欄位N from tb_name語句是select * from tb_name的優化。  1、執行效率。做一個實驗 select top 10000 gid,fariqi,reader,title from tgo

mysqlCOUNT()組函式、IFNULL()函式顯示引擎檢視資料庫版本等等

#COUNT()函式,或者說組函式/聚合函式/統計函式會忽略null值,即不把null值算進來 SELECT COUNT(commission_pct), COUNT(department_id), COUNT(*)FROM employees; /* MySQL中的IFNULL函式類似於Ora

mysql儲存過程使用select count(*) into 變數名 from +表+ where條件的用法

select count(*) into v_count from dual where userid=2;此語句的意思就是根據where條件查詢dual表,得到的行數存入變數v_count中(給變數賦值) 只能在儲存過程中編寫這樣的語句?如果在mysql的sql語句中編寫

ORACLE更新資料PLSQL DeveloperSELECT ... FOR UPDATE和 SELECT T.*,ROWID的區別

背景:ORACLE中更新少量資料時,在PLSQL  Developer中,一般用的語句是SELECT   FOR   UPDATE和SELECT   T.*,ROWID,這倆語句執行之後可以手動在查詢出來的資料中修改。例項背景:表名A,資料如下:  ACOL1    COL2

elasticsearch系列-ES對多個欄位聚合select A,B,COUNT(*) from table group by A,B

ES對多個欄位聚合,select A,B,COUNT(*)from table group by A,B 假設有下表 NAME SEX PROF 李誠 男 副教授 張旭 男 講師 王萍 女 助教 劉冰