Mysql性能優化:為什麼你的count(*)這麼慢?

来源:https://www.cnblogs.com/Chenjiabing/archive/2020/04/03/12625559.html
-Advertisement-
Play Games

導讀 在開發中一定會用到統計一張表的行數,比如一個交易系統,老闆會讓你每天生成一個報表,這些統計信息少不了 sql 中的count函數。 但是隨著記錄越來越多,查詢的速度會越來越慢,為什麼會這樣呢?Mysql內部到底是怎麼處理的? 今天這篇文章將從Mysql內部對於count函數是怎樣處理的? 本文 ...


導讀

  • 在開發中一定會用到統計一張表的行數,比如一個交易系統,老闆會讓你每天生成一個報表,這些統計信息少不了 sql 中的count函數。
  • 但是隨著記錄越來越多,查詢的速度會越來越慢,為什麼會這樣呢?Mysql內部到底是怎麼處理的?
  • 今天這篇文章將從Mysql內部對於count函數是怎樣處理的?
  • 本文首發於作者微信公眾號【碼猿技術專欄】Mysql性能優化:為什麼你的count(*)這麼慢?,原創不易,喜歡的請支持一下,謝謝!!!

count的實現方式

  • 在Mysql中的不同的存儲引擎對count函數有不同的實現方式。
  • MyISAM引擎把一個表的總行數存在了磁碟上,因此執行count(*)的時候會直接返回這個數,效率很高(沒有where查詢條件)。
  • InnoDB引擎並沒有直接將總數存在磁碟上,在執行count(*)函數的時候需要一行一行的將數據讀出來,然後累計總數。

為什麼InnoDB不將總數存起來?

  • 說到InnoDB相信讀者總會想到其支持事務的特性,事務具有隔離性,如果將總數存起來,怎麼保證各個事務之間的總數的一致性呢?不明白的看圖

  • 事務A事務B中的count(*)的執行結果是不同的,因此InnoDB引擎在每個事務中返回多少行是不確定的,只能一行一行的讀出來用來判斷總數。

如何提升count效率

  • InnoDB對於如何提升count(*)的查詢效率,網上有多種解決辦法,這裡主要介紹三種,並分析可行性。

show table status

  • show table status這個命令能夠很快的查詢出資料庫中每個表的行數,但是真的能夠替代count(*)嗎?
  • 答案是不能。原因很簡單,這個命令統計出來的值是一個「估值」,因此是不准確的,官方文檔說誤差大概在40%-50%
  • 因此這種方法直接pass,不准確還用它幹嘛。

緩存系統存儲總數

  • 這種方法也是最容易想到的,增加一行就+1,刪除一行就-1,並且緩存系統讀取也是很快,既簡單又方便的為什麼不用?

  • 緩存系統和Mysql是兩個系統,比如redisMysql這兩個是典型的比較。兩個系統最難的就是在高併發下無法保證數據的一致性。  

  • 通過上面兩張圖,無論是redis計數+1還是insert into user先執行,最終都會導致數據在邏輯上的不一致。第一張圖會出現redis計數少了,第二張圖雖然計數正確了但是並沒有查詢出插入的那一行數據。

  • 在併發系統裡面,我們是無法精確控制不同線程的執行時刻的,因為存在圖中的這種操作序列,所以,我們說即使Redis正常工作,這個計數值還是邏輯上不精確的。

在資料庫保存計數

  • 通過緩存系統保存的分析得知了使用緩存無法保證數據在邏輯上的一致性,因此我們想到了直接使用資料庫來保存,有了「事務」的支持,也就保證了數據的一致性了。

  • 如何使用呢?很簡單,直接將計數保存在一張表中(table_name,total)

  • 至於執行的邏輯只需要將緩存系統中redis計數+1改成total欄位+1即可,如下圖: 

  • 由於在同一個事務中,保證了數據在邏輯上的一致性。

不同count的用法

  • count()是一個聚合函數,對於返回的結果集,一行行地判斷,如果count函數的參數不是NULL,累計值就加1,否則不加。最後返回累計值。
  • count的用法有多種,分別是count(*)count(欄位)count(1)count(主鍵id)。那麼多種用法,到底有什麼差別呢?當然,「前提是沒有where條件語句」
  • count(id):InnoDB引擎會遍歷整張表,把每一行的id值都取出來,返回給server層。server層拿到id後,判斷是不可能為空的,就按行累加。
  • count(1):InnoDB引擎遍歷整張表,但不取值。server層對於返回的每一行,放一個數字1進去,判斷是不可能為空的,按行累加。
  • count(欄位)count(*):不會把全部欄位取出來,而是專門做了優化,不取值。count(*)肯定不是null,按行累加。
    • 如果這個“欄位”是定義為not null的話,一行行地從記錄裡面讀出這個欄位,判斷不能為null,按行累加;
    • 如果這個欄位定義允許為null,那麼執行的時候,判斷到有可能是null,還要把值取出來再判斷一下,不是null才累加。
  • 所以結論很簡單:「按照效率排序的話,count(欄位)<count(主鍵id)<count(1)count(*),所以建議讀者,儘量使用count(*)。」
  • 「註意」:這裡肯定有人會問,count(id)不是走的索引嗎,為什麼查詢效率和其他的差不多呢?陳某在這裡解釋一下,雖然走的索引,但是還是要一行一行的掃描才能統計出來總數。

總結

  • MyISAM表雖然count(*)很快,但是不支持事務;
  • show table status命令雖然返回很快,但是不准確;
  • InnoDB直接count(*)會遍歷全表(沒有where條件),雖然結果準確,但會導致性能問題。
  • 緩存系統的存儲計數雖然簡單效率高,但是無法保證數據的一致性。
  • 資料庫保存計數很簡單,也能保證數據的一致性,建議使用。
  • 「思考題,讀者留言區討論」:在系統高併發的情況下,使用資料庫保存計數,是先更新計數+1,還是先插入數據。即是先update total+=1還是先insert into

 


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

-Advertisement-
Play Games
更多相關文章
  • Cannot connect to the Docker daemon. Is the docker daemon running on this host? 原因: 沒有啟動docker服務 service docker start 效果: docker stop showdoc # 停止容器 d ...
  • 在目錄下創建新文件時出現 ,原因是用戶許可權不足。 解決方法是給用戶添加修改許可權,在根目錄執行以下命令: Linux/Unix 的文件調用許可權分為三級 : 文件擁有者、群組、其他。利用 chmod 可以藉以控制文件如何被他人所調用。 語法為: R : 對目前目錄下的所有文件與子目錄進行相同的許可權變更( ...
  • MySQL是一個開放源碼的小型關聯式資料庫管理系統,開發者為瑞典MySQL AB公司, 目前屬於Oracle公司,MySQL被廣泛地應用在Internet上的中小型網站中。由於其體積小、速度快、總體擁有成本低,尤其是開放源碼這一特點,許多中小型網站為了降低網站總體擁有成本而選擇了MySQL作為網站數 ...
  • 1、 Linux操作系統簡介 Linux具有如下優點: 穩定、免費或者花費少 安全性高 多任務,多用戶 耗資源少 由於內核小,所以它可以支持多種電子產品,如:Android手機、PDA等。 2、 Linux發展趨勢 隨著IT產業的不斷發展,用戶對網站體驗要求也越來越高,目前主流網站後端承載系統都是L ...
  • https://www.cnblogs.com/wt7018/p/11929359.html MongoDB聚合(aggregate) 一、基礎 1、什麼是聚合? 聚合是基於數據處理的聚合管道,每個文檔通過一個有多個階段(stage)組成的管道可以對每個階段的管道進行分組、過濾等功能,然後經過一系列 ...
  • 1. 業務說:“…… bulabula……,這個需求很簡單,怎麼實現我不管?” 面對霸氣側漏的業務需求,由於沒有大數據知識儲備,咱心裡沒底,咱也不敢問,咱也不敢說,只能靜下來默默儲備、默默尋覓解決方案。 關註“一猿小講”公眾號的小伙伴們,今天有福啦,因為今天我們將一起跳出系統之外,共同邁入大數據之 ...
  • 環境 MySQL5.6 表結構及數據 sql DROP TABLE IF EXISTS ; CREATE TABLE ( int(11) NOT NULL AUTO_INCREMENT, varchar(20) NOT NULL, varchar(20) NOT NULL, double(10, 3 ...
  • SQL語句還是多去用才能掌握,再多理論,白搭 SQL概述 SQL的產生與發展 SQL的特點 SQL功能十分強大,針對數據的操作,核心功能只用9個動詞就可以完成。而且其語句有點類似英語口語一看基本就能明白它要表達的意思。 SQL語言對資料庫三級模式的支持 SQL語言作為大多數資料庫使用的共同數據存取語 ...
一周排行
    -Advertisement-
    Play Games
  • GoF之工廠模式 @目錄GoF之工廠模式每博一文案1. 簡單說明“23種設計模式”1.2 介紹工廠模式的三種形態1.3 簡單工廠模式(靜態工廠模式)1.3.1 簡單工廠模式的優缺點:1.4 工廠方法模式1.4.1 工廠方法模式的優缺點:1.5 抽象工廠模式1.6 抽象工廠模式的優缺點:2. 總結:3 ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 本章將和大家分享ES的數據同步方案和ES集群相關知識。廢話不多說,下麵我們直接進入主題。 一、ES數據同步 1、數據同步問題 Elasticsearch中的酒店數據來自於mysql資料庫,因此mysql數據發生改變時,Elasticsearch也必須跟著改變,這個就是Elasticsearch與my ...
  • 引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...