dbgrideh 為什么只一行_Mysql性能優化:為什么count(*)這么慢?

導讀

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

count的實現方式

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

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

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

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

如何提升count效率

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

show table status

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

緩存系統存儲總數

  • 這種方法也是最容易想到的,增加一行就+1,刪除一行就-1,并且緩存系統讀取也是很快,既簡單又方便的為什么不用?
  • 緩存系統和Mysql是兩個系統,比如redisMysql這兩個是典型的比較。兩個系統最難的就是在高并發下無法保證數據的一致性。通過以下兩圖我們來理解一下:

35978d8fae0637dfdd53ee6738494455.png

78bfd363a111f13c057e50187dd10ec3.png
  • 通過上面兩張圖,無論是redis計數+1還是insert into user先執行,最終都會導致數據在邏輯上的不一致。第一張圖會出現redis計數少了,第二張圖雖然計數正確了但是并沒有查詢出插入的那一行數據。
  • 在并發系統里面,我們是無法精確控制不同線程的執行時刻的,因為存在圖中的這種操作序列,所以,我們說即使Redis正常工作,這個計數值還是邏輯上不精確的。

在數據庫保存計數

  • 通過緩存系統保存的分析得知了使用緩存無法保證數據在邏輯上的一致性,因此我們想到了直接使用數據庫來保存,有了「事務」的支持,也就保證了數據的一致性了。
  • 如何使用呢?很簡單,直接將計數保存在一張表中(table_name,total)。
  • 至于執行的邏輯只需要將緩存系統中redis計數+1改成total字段+1即可,如下圖:

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

不同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(字段):
  • 如果這個“字段”是定義為not null的話,一行行地從記錄里面讀出這個字段,判斷不能為null,按行累加;
  • 如果這個字段定義允許為null,那么執行的時候,判斷到有可能是null,還要把值取出來再判斷一下,不是null才累加。
  • count(*):不會把全部字段取出來,而是專門做了優化,不取值。count(*)肯定不是null,按行累加。
  • 所以結論很簡單:「按照效率排序的話,count(字段)<count(主鍵id)<count(1)≈count(*),所以建議讀者,盡量使用count(*)。」
  • 「注意」:這里肯定有人會問,count(id)不是走的索引嗎,為什么查詢效率和其他的差不多呢?陳某在這里解釋一下,雖然走的索引,但是還是要一行一行的掃描才能統計出來總數。

總結

  • MyISAM表雖然count(*)很快,但是不支持事務;
  • show table status命令雖然返回很快,但是不準確;
  • InnoDB直接count(*)會遍歷全表(沒有where條件),雖然結果準確,但會導致性能問題。
  • 緩存系統的存儲計數雖然簡單效率高,但是無法保證數據的一致性。
  • 數據庫保存計數很簡單,也能保證數據的一致性,建議使用。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/533679.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/533679.shtml
英文地址,請注明出處:http://en.pswp.cn/news/533679.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

jmeter 高并發測試報告_JMeter分布式測試

一、為什么要使用分布式測試按照一般的壓力機配置&#xff0c;jmeter的GUI模式下(Windows)&#xff0c;最多支持300左右的模擬請求線程&#xff0c;再大的話&#xff0c;容易造成卡頓、無響應等情況&#xff0c;這是限于jmeter其本身的機制和硬件配置。有時候為了盡量模擬業務場…

登陸攔截攔截ajax,過濾器實現登錄攔截需要注意的問題(AJAX請求的處理)

1.問題描述&#xff1a;最近自己在寫demo時遇到一個問題&#xff0c;在ajax請求時用Filter做登錄攔截&#xff0c;結果頁面不跳轉(Ajax是不能做轉發和重定向的)、、、、最終的最終在同事zt的提示下&#xff0c;恍然大悟&#xff0c;雖然很基本的問題&#xff0c;但也糾結了好久…

半圓陰影_六年級數學:怎么求陰影部分面積?正方形與半圓,割補法常考題

歡迎您來到方老師數學課堂&#xff0c;請點擊上方藍色字體&#xff0c;添加關注。所有的視頻內容&#xff0c;全部免費&#xff0c;請大家放心關注&#xff0c;放心訂閱。六年級數學&#xff1a;怎么求陰影部分面積&#xff1f;正方形與半圓&#xff0c;割補法常考題。大家先在…

c語言判斷整數_用c++編寫閏年的判斷基礎程序

其實c語言與c語言有太多共同的東西&#xff0c;學習過c語言再學習c語言就顯得輕而易舉。當然學過了c再去學習c語言也是有一些幫助的(但是個人不提倡先學習c在學c語言)。由于現在經常看見有關閏年的程序&#xff0c;風式各樣&#xff0c;眼花繚亂&#xff0c;些許凌亂&#xff0…

cat日志 搜索_大日志,看我如何對付你

在服務器接口測試中&#xff0c;我們經常會和各種日志打交道。一旦測試時服務端出現了問題&#xff0c;而單憑服務端的日志又不能發現問題原因的時候&#xff0c;往往開發要向我們測試人員詢問客戶端這邊的情況&#xff0c;希望看看我們能不能提供一些有用信息&#xff0c;如錯…

python編譯成dll文件_用vc生成可被python調用的dll文件

前提已經有.c 和.i文件 用swid編譯了.i文件生成了wrap.c文件和.py文件 vc創建dll工程 將.h加入到頭文件中.c文件和wrap.c文件添加到源文件中 將.i文件添加到工程目錄下 Tools->Options->Directories中修改include 和lib 添加python里的include 和libs 把\libs\python27.l…

加載gif動圖_GIF生成神器——ScreenToGif

每次需要做一個動圖展示時&#xff0c;總是感覺很頭疼。截圖吧&#xff0c;需要的圖片太多&#xff1b;錄視頻吧&#xff0c;文件太大&#xff1b;做動圖吧&#xff0c;太麻煩。今天推薦的這個軟件或許能夠解決大家這個困惑&#xff0c;今天推薦的是動圖生成神器——ScreenToGi…

vue底部選擇器_vue實現動態顯示與隱藏底部導航的方法分析

vue實現動態顯示與隱藏底部導航的方法分析本文實例講述了vue實現動態顯示與隱藏底部導航的方法。分享給大家供大家參考&#xff0c;具體如下&#xff1a;在日常項目中&#xff0c;總有幾個頁面是要用到底部導航的&#xff0c;總有那么些個頁面&#xff0c;是不需要底部導航的&a…

java 修改最大nio連接數_關于java流的幾個概念:IO、BIO、NIO、AIO,有幾個人全知道?...

關于同步、阻塞的知識我之前的文章有介紹&#xff0c;所以關于流用到這些概念與之前多線程用的概念一樣。下面具體來看看java中的幾種流IO/BIOBIO就是指IO&#xff0c;即傳統的Blocking IO,即同步并阻塞的IO。這也是jdk1.4之前的唯一選擇&#xff0c;依賴于ServerSocket實現&am…

python神秘的魔法函數_python魔法函數

一、參考二、構造和初始化2.1 __new__在對象實例化過程中最先調用的方法是__new__, 該方法接收參數為類&#xff0c;然后將其他參數&#xff0c;傳遞給__init__, 該魔法函數比較少見&#xff0c;可以使用其&#xff0c;創建單例類; __new__方法是一個類方法&#xff0c;需要攜帶…

python掃雷 廣度優先_廣度優先搜索(BFS)解題總結

定義 廣度優先搜索算法&#xff08;Breadth-First-Search&#xff09;&#xff0c;是一種圖形搜索算法。 簡單的說&#xff0c;BFS是從根節點開始&#xff0c;沿著樹(圖)的寬度遍歷樹(圖)的節點。 如果所有節點均被訪問&#xff0c;則算法中止。 BFS同樣屬于盲目搜索。 一般用隊…

python默認參數陷阱_python默認參數陷阱

0|1陷阱&#xff1f;學過函數的人一定聽說過函數的默認參數&#xff0c;關于函數的默認參數&#xff0c;請看以下的例子&#xff1a;def extendList(val, lst[]):lst.append(val)return lstlist1 extendList(10)list2 extendList(123, [])print(list1 %s % list1)print(list…

python裁剪圖片并保存_python – 如何從圖像中剪切輪廓并將其保存到新文件中

大家好,這是我的第一個問題所以請保持溫和.我有一個計算機視覺領域的項目,我是新的,我會很感激一些幫助.我有一個pcb的圖像,我的(首先)任務是從背景中切斷電路板并將其保存到新文件.如果結果只是沒有灰色背景的普通pcb,那就沒問題了. 我到目前為止嘗試的是,首先使用閾值將圖像轉…

opencv如何把一個矩陣不同列分離開_學習OPEN_CV

OpenCv中文論壇精華地址http://www.opencv.org.cn/index.php/User:Ollydbg23http://sivp.sourceforge.net/(sivp)一、基礎操作1. 數據類型 數據結構了解圖像相關&#xff1a;cvArr cvMat IplImage數據數組的維數&#xff0c; 與數據的通道數 見P46 (76)2. 常見的矩陣操作熟悉3…

python文件合并_用Python 將兩個文件的內容合并成一個新的文件.

一個文件的內容是:IntroductiontoProgramming,NetworkingFundamentals,InternetworkingTechnologies,PlatformTechnologies,InformationTechnologyforUsers,ComputerForensics,Enterpr... 一個文件的內容是: Introduction to Programming, Networking Fundamentals, Internetwo…

flash代碼_Flash如何對制作文件進行優化

對FLASH進行優化分為兩方面&#xff0c;一方面是代碼上的優化&#xff0c;主要是通過優化提高FLASH性能&#xff0c;降低CPU占用和內存使用。另一方面是資源的優化&#xff0c;這方面的優化是為了減小編譯后的文件大小以及制作文件的大小&#xff0c;因為如果不進行相應的優化&…

潛流式濕地計算_人工濕地計算書

人工濕地計算書1、尾水提升泵房集水池基本參數集水池設計規模為30000m3/d&#xff0c;約折合1250m3/h&#xff0c;按水力停留時間HRT為0.25 h計&#xff0c;集水井有效容積應為312.5 m3&#xff0c;考慮到與污水廠原有排污管道相契合&#xff0c;集水設計尺寸為&#xff1a;LBH…

deepin系統轉為windows_windows系統下安裝深度系統deepin

前期準備DiskGenius(用來擴展分區)deepin-20-amd64.iso(深度系統鏡像文件)相關文件下載首先下載安裝時要用的工具&#xff0c;分別為:DiskGenius , UltraISODiskGenius是一款磁盤工具&#xff0c;創建系統分區。UltraISO是用來打開系統光盤鏡像文件工具。Win8/8.1/10無需下載Ul…

c3等待加載樣式 vue_Vue.js__簡易加載等待動畫

Vue.js__簡易加載等待動畫Vue實現為覽或講瑣了過自系一讀頁圍這就多網解元當維自加&#xff0c;加載動畫的樣式取自其他出處&#xff0c;侵直分調瀏器代&#xff0c;剛求的一學礎過功互有解小久宗點差維含數刪。將Vue屬性覽或講瑣了過自系一讀頁圍這就多網解元當維和方法復制到…

軟件開發模型_QT開發(二十三)——軟件開發流程

一、軟件開發流程簡介軟件開發流程是通過一系列步驟保證軟件產品的順利完成&#xff0c;是軟件產品在生命周期內的管理學。軟件開發流程的本質是軟件開發流程與具體技術無關&#xff0c;是開發團隊必須遵守開的規則。二、常見軟件開發流程模型常見的軟件開發流程模型包括即興模…