總結
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(字段)來說:
- 如果這個字段是定義為not null的話,一行一行讀取這個字段,判斷不能為null,按行累加
- 如果這個字段定義為允許null,判斷到有可能為null,還要把值取出來再判斷一下,不是null才累加
count(*) 是個例外,并不會把全部字段都取出來,而是專門做了優化,不取值,count(*)肯定不是null,按行累加
結論(性能從高到低):
count(*) > count(1) > count(id) > count(字段)
大資料量的mis系統,清單頁分頁如何讀取總數?
- 寫死總數,mis背景内部使用,本來精度要求就不高,大部分用搜尋就可以滿足了 ,簡單快捷
- 單獨redis計數,定時腳本修正資料 ,簡單,存在部分誤差
- mysql統計表,通過事務保證一緻性,性能差,維護複雜度高
分頁如何優化
- 改為 id>xxx limit m 根據排序條件建立索引,記錄開始的位置
- 利用覆寫索引,減少無效回表。