天天看點

mysql中count(x)到底慢不慢

總結

MyISAM 表不支援事務,但是count(*) 很快,因為他直接記錄了一個總數

MyISAM在統計表的總行數的時候會很快,但是有個大前提,不能加有任何WHERE條件。這是因為:MyISAM對于表的行數做了優化,具體做法是有一個變量存儲了表的行數,如果查詢條件沒有WHERE條件則是查詢表中一共有多少條資料,MyISAM可以做到迅速傳回,是以也解釋了如果加WHERE條件,則該優化就不起作用了。細心的同學會發現,innodb的表也有這麼一個存儲了表行數的變量,但是很遺憾這個值是一個估計值,沒有什麼實際意義。

show table status  雖然很快,但是不精準

InnoDB 表直接 count(*) 會周遊全表,雖然結果準确,但是性能很差

count(*)   count(id)  count(1)  count(字段) 性能對比

count的定義:

COUNT()有兩個非常不同的作用:

1.它可以統計某個列值的數量,也可以統計行數。在統計列值時要求列值是非空的(不統計NULL)。如果在COUNT()的括号中定了列或者清單達式,則統計的就是這個表達式有值的結果數。

2.COUNT()的另一個作用是統計結果集的行數。當MySQL确認括号内的表達式值不可能為空時,實際上就是在統計行數。最簡單的就是當我們使用COUNT(*)的時候,這種情況下通配符*并不像我們猜想的那樣擴充成所有的列,實際上,他會忽略所有列而直接統計所有的行數“

count(id) InnoDB會周遊整個表,把每一行的id都取出來,傳回給server層。server層拿到id後,判斷是不可能為空的,就按行累加

count(1) InnoDB會周遊整個表,不取值。server層放一個數字1進去,判斷是不可能為空的,按行累加

是以:count(1) 比 count(id) 快,因為從引擎傳回id會涉及到解析資料,copy字段值等操作

count(字段)來說:

  1. 如果這個字段是定義為not null的話,一行一行讀取這個字段,判斷不能為null,按行累加
  2. 如果這個字段定義為允許null,判斷到有可能為null,還要把值取出來再判斷一下,不是null才累加

count(*) 是個例外,并不會把全部字段都取出來,而是專門做了優化,不取值,count(*)肯定不是null,按行累加

結論(性能從高到低):

count(*) > count(1) >  count(id) > count(字段)

大資料量的mis系統,清單頁分頁如何讀取總數?

  1. 寫死總數,mis背景内部使用,本來精度要求就不高,大部分用搜尋就可以滿足了 ,簡單快捷
  2. 單獨redis計數,定時腳本修正資料 ,簡單,存在部分誤差
  3. mysql統計表,通過事務保證一緻性,性能差,維護複雜度高

分頁如何優化

  1. 改為 id>xxx  limit m 根據排序條件建立索引,記錄開始的位置
  2. 利用覆寫索引,減少無效回表。