http://blog.itpub.net/15480802/viewspace-755582/
在服務器級別只提供了query cache,而在存儲引擎級別,MyISAM和InnoDB分別引入了key cache和buffer pool
什么是query cache
Mysql沒有shared_pool緩存執行計划,但是提供了query cache緩存sql執行結果和文本,如果在生命周期內完全相同的sql再次運行,則連sql解析都免去了;
所謂完全相同,包含如下條件
Sql的大小寫必須完全一樣;
發起sql的客戶端必須使用同樣的字符集和通信協議;
sql查詢同一數據庫下的同一個表(不同數據庫可能有同名表);
Sql查詢結果必須確定,即不能帶有now()等函數;
當查詢表發生DML或DDL,其緩存即失效;
針對mysql/information_schema/performance_schema的查詢不緩存;
使用臨時表的sql也不能緩存;
開啟緩存后,每個select先檢查是否有可用緩存(必須對這些表有select權限),而每個寫入操作先執行查詢語句並使相關緩存失效;
5.5起可緩存基於視圖的查詢
Mysql維護一個hash表用來查找緩存,其key為sql text,數據庫名以及客戶端協議的版本等
相應參數
Have_query_cache:服務器是否支持查詢緩存
Query_cache_type:0(OFF)不緩存;1(ON)緩存查詢但不包括使用SQL_NO_CACHE的sql;2(DEMAND)只緩存使用SQL_CACHE的sql
Query_cache_size:字節為單位,即使query_cache_type=0也會為分配該內存,所以應該一並設置為0
Query_cache_limit:允許緩存的最大結果集,大於此的sql不予緩存
Query_cache_min_res_limit:用於限定塊的最小尺寸,默認4K;
緩存的metadata占有40K內存,其可分為大小不等的多個子塊,各塊之間使用雙向鏈表鏈接;根據其功能分別存儲查詢結果,基表和sql text等;
每個sql至少用到兩個塊:分別存儲sql文本和查詢結果,查詢引用到的表各占一個塊;
為了減少響應時間,每產生1行數據就發送給客戶端;
數據庫啟動時調用malloc()分配查詢緩存
查詢緩存擁有一個全局鎖,一旦有會話獲取就會阻塞其他訪問緩存的會話,因此當緩存大量sql時,緩存invalidation可能會消耗較長時間;
Innodb也可以使用查詢緩存,每個表在數據字典中都有一個事務ID計數器,ID小於此值的事務不可使用緩存;表如果有鎖(任何鎖)則也不可使用查詢緩存;
狀態變量
有關query cache的狀態變量都以Qcache打頭
mysql> SHOW STATUS LIKE 'Qcache%';
+-------------------------+--------+
| Variable_name | Value |
+-------------------------+--------+
| Qcache_free_blocks | 36 |
| Qcache_free_memory | 138488 |
| Qcache_hits | 79570 |
| Qcache_inserts | 27087 |
| Qcache_lowmem_prunes | 3114 |
| Qcache_not_cached | 22989 |
| Qcache_queries_in_cache | 415 |
| Qcache_total_blocks | 912 |
+-------------------------+--------+
Qcache_inserts—被加到緩存中query數目
Qcache_queries_in_cache—注冊到緩存中的query數目
緩存每被命中一次,Qcache_hits就加1;
計算緩存query的平均大小=(query_cache_size-Qcache_free_memory)/Qcache_queries_in_cache
Com_select = Qcache_not_cached + Qcache_inserts + queries with errors found during the column-privileges check
Select = Qcache_hits + queries with errors found by parser
Buffer pool
innodb即緩存表又緩存索引,還有設置多個緩沖池以增加並發,很像oracle
采用LRU算法:
所有buffer塊位於同一列表,其中后3/8為old,每當新讀入一個數據塊時,先從隊尾移除同等塊數然后插入到old子列的頭部,如再次訪問該塊則將其移至new子列的頭部
Innodb_buffer_pool_size: buffer pool大小
Innodb_buffer_pool_instances: 子buffer pool數量,buffer pool至少為1G時才能生效
Innodb_old_blocks_pct: 范圍5 – 95, 默認為37即3/8,指定old子列的比重
Innodb_old_blocks_time: 以ms為單位,新插入old子列的buffer塊必須等待指定時間后才能移入new列,適用於one-time scan頻繁的操作,以避免經常訪問的數據塊被剔出buffer pool
可通過狀態變量獲知當前buffer pool的運行信息
Innodb_buffer_pool_pages_total:緩存池總頁數
Innodb_buffer_pool_bytes_data:當前buffer pool緩存的數據大小,包括臟數據
Innodb_buffer_pool_pages_data:緩存數據的頁數量
Innodb_buffer_pool_bytes_dirty:緩存的臟數據大小
Innodb_buffer_pool_pages_diry:緩存臟數據頁數量
Innodb_buffer_pool_pages_flush:刷新頁請求數量
Innodb_buffer_pool_pages_free:空閑頁數量
Innodb_buffer_pool_pages_latched:緩存中被latch的頁數量,這些頁此刻正在被讀或寫;然而計算此變量比較消耗資源,只有在UNIV_DEBUG被定義了才可用
相關源代碼如下
#ifdef UNIV_DEBUG
{"buffer_pool_pages_latched",
(char*) &export_vars.innodb_buffer_pool_pages_latched, SHOW_LONG},
#endif /* UNIV_DEBUG */
Innodb_buffer_pool_pages_misc:用於維護諸如行級鎖或自適應hash索引的內存頁=總頁數-空閑頁-使用的頁數量
Innodb_buffer_pool_read_ahead:預讀入緩存的頁數量
Innodb_buffer_pool_read_ahead_evicted:預讀入但是1次都沒用就被剔出緩存的頁
Innodb_buffer_pool_read_requests:InnoDB的邏輯讀請求次數
Innodb_buffer_pool_reads:直接從磁盤讀取數據的邏輯讀次數
Innodb_buffer_pool_wait_free:緩存中沒有空閑頁滿足當前請求,必須等待部分頁回收或刷新,記錄等待次數
Innodb_buffer_pool_write_requests:向緩存的寫數量
可使用innodb standard monitor監控buffer pool的使用情況,主要有如下指標:
Old database pages: old子列中的頁數
Pages made young, not young: 從old子列移到new子列的頁數,old子列中沒有被再次訪問的頁數
Youngs/s non-youngs/s: 訪問old並導致其移到new列的次數
Key cache
5.5僅支持一個結構化變量,即key cache,其包含4個部件
Key_buffer_size
Key_cache_block_size:單個塊大小,默認1k
Key_cache_division_limit:warm子列的百分比(默認100),key cache buffer列表的分隔點,用於分隔host和warm子列表
Key_cache_age_threshold:頁在hot子列中的生命周期,值越小則越快的移至warm列表
MyISAM只緩存索引,
可創建多個key buffer—set global hot_cache.key_buffer_size=128*1024
索引指定key buffer—cache index t1 in hot_cache
可在數據庫啟動時load index into key_buffer提前加載緩存,也可通過配置文件自動把索引映射到key cache
key_buffer_size = 4G
hot_cache.key_buffer_size = 2G
cold_cache.key_buffer_size = 2G
init_file=/path/to/data-directory/mysqld_init.sql
mysqld_init.sql內容如下
CACHE INDEX db1.t1, db1.t2, db2.t3 IN hot_cache
CACHE INDEX db1.t4, db2.t5, db2.t6 IN cold_cache
默認采用LRU算法,也支持名為中間點插入機制midpoint insertion strategy
索引頁剛讀入key cache時,被放在warm列的尾部,被訪問3次后則移到hot列尾並循環移動,如果在hot列頭閑置連續N次都沒訪問到,則會被移到warm列頭,成為被剔出cache的首選;
N= block no* key_cache_age_threshold/100