-------------------------------------------------------------------------------------------------第一篇-------------------------------------------------------------------------------------------------------------------mysql
sql調優,主要是考慮下降:consistent gets和physical reads的數量。sql
count(1)與count(*)比較:數據庫
若是你的數據表沒有主鍵,那麼count(1)比count(*)快
若是有主鍵的話,那主鍵(聯合主鍵)做爲count的條件也比count(*)要快
若是你的表只有一個字段的話那count(*)就是最快的啦
count(*) count(1) 二者比較。主要仍是要count(1)所相對應的數據字段。
若是count(1)是聚索引,id,那確定是count(1)快。可是差的很小的。
由於count(*),自動會優化指定到那一個字段。因此不必去count(?),用count(*),sql會幫你完成優化的性能優化
count詳解:函數
count(1)
跟count(主鍵)
同樣,只掃描主鍵。性能
count(*)
跟count(非主鍵)
:測試
count(*)將返回表格中全部存在的行的總數包括值爲null的行,然而count(列名)將返回表格中除去null之外的全部行的總數(有默認值的列也會被計入).
distinct 列名,獲得的結果將是除去值爲null和重複數據後的結果優化
count(主鍵) 不必定比count(其他索引) 快: 搜索引擎
索引是一種B+樹的結構,以塊爲單位進行存儲。假設塊大小是1K,主鍵索引大小爲4B,有一個字段A的索引大小爲2B。
一樣一個塊,能存放256個主鍵索引,可是能存放512個字段A的索引。
假設總數據是2K條,意味着主鍵索引佔用了8個塊,而A字段索引佔用了4個塊,統計時用主鍵索引須要經歷的塊多,IO次數多。效率也比A字段索引慢。spa
1.若是在開發中確實須要用到count()聚合,那麼優先考慮count(*),由於mysql數據庫自己對於count(*)作了特別的優化處理。
有主鍵或聯合主鍵的狀況下,count(*)略比count(1)快一些。
沒有主鍵的狀況下count(1)比count(*)快一些。
若是表只有一個字段,則count(*)是最快的。
2.使用count()聚合函數後,最好不要跟where age = 1;這樣的條件,會致使不走索引,下降查詢效率。除非該字段已經創建了索引。使用count()聚合函數後,如有where條件,且where條件的字段未創建索引,則查詢不會走索引,直接掃描了全表。
3.count(字段),非主鍵字段,這樣的使用方式最好不要出現。由於它不會走索引.
--------------------------------------------------------------------------------第二篇----------------------------------------------------------------------------------------------------------------
首先,以咱們最多見的兩種數據庫表引擎MyISAM和Innodb來說。
MyISAM在統計表的總行數的時候會很快,可是有個大前提,不能加有任何WHERE條件。這是由於:MyISAM對於表的行數作了優化,具體作法是有一個變量存儲了表的行數,若是查詢條件沒有WHERE條件則是查詢表中一共有多少條數據,MyISAM能夠作到迅速返回,因此也解釋了若是加WHERE條件,則該優化就不起做用了。細心的同窗會發現,innodb的表也有這麼一個存儲了錶行數的變量,可是很遺憾這個值是一個估計值,沒有什麼實際意義。
在該引擎下,COUNT(1)和COUNT(*)哪一個快呢?結論是:這倆在高版本的MySQL(5.5及之後,5.1的沒有考證)是沒有什麼區別的,也就沒有COUN(1)會比COUNT(*)更快這一說了。
WHY?這就要從COUNT()函數的具體含義提及了。」
COUNT()有兩個很是不一樣的做用:它能夠統計某個列值的數量,也能夠統計行數。在統計列值時要求列值是非空的(不統計NULL)。若是在COUNT()的括號中定了列或者列表達式,則統計的就是這個表達式有值的結果數。......COUNT()的另外一個做用是統計結果集的行數。當MySQL確認括號內的表達式值不可能爲空時,實際上就是在統計行數。最簡單的就是當咱們使用COUNT(*)的時候,這種狀況下通配符*並不像咱們猜測的那樣擴展成全部的列,實際上,他會忽略全部列而直接統計全部的行數「——《高性能MySQL》。
一般,咱們將第一個字段(通常是ID)做爲主鍵,那麼這個時候COUNT(1)實際統計的就是行數(此處表達有誤,詳見文章結尾),由於主鍵確定是非NULL的。問題是Innodb是經過主鍵索引來統計行數的嗎?結論是:若是該表只有一個主鍵索引,沒有任何二級索引的狀況下,那麼COUNT(*)和COUNT(1)都是經過經過主鍵索引來統計行數的。若是該表有二級索引,則COUNT(1)和COUNT(*)都會經過佔用空間最小的字段的二級索引進行統計,也就是說雖然COUNT(1)指定了第一列(此處表達有誤,詳見文章結尾)可是innodb不會真的去統計主鍵索引(通常爲第一個字段的索引)。
新建一張基於Innodb的表,只有一個ID主鍵,並插入5w的測試數據,建表語句以下:
CREATE TABLE `tb_news` ( `id` bigint(21) NOT NULL AUTO_INCREMENT, `title` varchar(50) NOT NULL, `content` mediumtext NOT NULL, `count_ass` char(1) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=50001 DEFAULT CHARSET=utf8
這個時候執行COUNT(1)和COUNT(*)能夠看到解釋器的結果以下(二者一致,因此就只截了一張圖),能夠看到,二者都用了主鍵索引進行行數的統計:
新建一個二級索引title,以後在分別看一下COUNT(1)和COUNT(*)的解釋器結果(二者依然徹底一致),這時已經用二級索引進行統計而非主鍵索引:
在咱們以前特意預留的一個小字段count_ass字段建一個索引,到這一步目前表中有三個索引:一個主鍵索引,兩個二級索引。
這時候咱們再看一下COUNT(1)和COUNT(*)會經過哪一個索引來統計行數(二者仍是一致)。
目前基於磁盤的數據庫或者搜索引擎(好比Lucene)的性能瓶頸主要都是在IO階段,相比於CPU和RAM,IO操做實在太慢了,因此這類系統的優化方向也都都是相似的——盡一切可能減小IO的次數(因此不少用ES的程序在性能優化到極限的時候選擇直接上SSD)。這裏統計行數的操做,查詢優化器的優化方向就是選擇可以讓IO次數最少的索引,也就是基於佔用空間最小的字段所建的索引(每次IO讀取的數據量是固定的,索引佔用的空間越小所需的IO次數也就越少)。而Innodb的主鍵索引是聚簇索引(包含了KEY,除了KEY以外的其餘字段值,事務ID和MVCC回滾指針)因此主鍵索引必定會比二級索引(包含KEY和對應的主鍵ID)大,也就是說在有二級索引的狀況下,通常COUNT()都不會經過主鍵索引來統計行數,在有多個二級索引的狀況下選擇佔用空間最小的。
若是說有張Innodb的表只有主鍵索引,並且記錄還比較大(好比30K),則統計行的操做會很是慢,由於IO次數會不少(這裏就不作實驗截圖了,有興趣能夠本身試一下)。
一個優化方案就是預先建一個小字段並建二級索引專門用來統計行數,極端狀況下這種優化速度提升上千倍也是正常的。
結論就是對於COUNT(1)和COUNT(*)執行優化器的優化是徹底同樣的,並無COUNT(1)會比COUNT(*)快這個說法