參考連接:html
https://blog.csdn.net/miyatang/article/details/54881547 https://blog.csdn.net/wyzxg/article/details/7700394?utm_source=copy mysql https://blog.csdn.net/qq_27529917/article/details/78454947算法 http://www.cnblogs.com/zyzloner/p/6727676.htmlsql http://www.ywnds.com/?p=9886數據庫 |
mysql內存:分爲全局共享內存和線程獨享內存,相似Oracle裏的SGA和PGA.緩存
1.全局共享內存:安全
InnoDB Buffer Pool:存儲InnoDB數據和索引。 ---innodb_buffer_pool_size InnoDB Additional Memory Pool:InnoDB 字典信息緩存 --innodb_additional_mem_pool_size redo log buffer:redo日誌緩衝區。 ---innodb_log_buffer_size Query Cache:存儲查詢緩存的。 ---query_cache_size Thread Cache:緩存鏈接線程的。 ----thread_cache_size Table Open Cache:緩存表文件句柄信息的。 ----table_open_cache Key Buffer:緩存MyISAM存儲引擎索引鍵的。 ----key_buffer_size |
2.global buffer(SGA, 全局內存分配總和)服務器
global buffer(SGA, 全局內存分配總和) = innodb_buffer_pool_size -- InnoDB高速緩衝,行數據、索引緩衝,以及事務鎖、自適應哈希等數據結構 +innodb_additional_mem_pool_size -- InnoDB數據字典額外內存,緩存全部表數據字典多線程 +innodb_log_buffer_size -- InnoDB REDO日誌緩衝,提升REDO日誌寫入效率 +key_buffer_size -- MyISAM表索引高速緩衝,提升MyISAM表索引讀寫效率 +query_cache_size -- 查詢高速緩存,緩存查詢結果,提升反覆查詢返回效率 +table_cahce -- 表空間文件描述符緩存,提升數據表打開效率 +table_definition_cache |
3.LSN
什麼是LSN: LSN(Log Sequence Number 日誌序列號),數據庫內部記錄數據庫時間的值,爲單調遞增的long long 類型。
LSN的做用:
每一個數據頁有LSN,重作日誌有LSN,checkpoint有LSN。
在每一個Page頭部和尾部都有對應的這個頁第一次修改LSN號和最新一次修改LSN號。
LSN
主要用於發生
crash
時對數據進行
recovery
,
LSN
是一個一直遞增的整型數字,
mysql中是按照寫入redo的事務日誌的字節數來增加得。
5.6.3以後佔用
8
字節,
在每一個數據頁頭部也會有對應的
LSN
號,該
LSN
記錄當前頁最後一次修改的
LSN
號,用於在
recovery
時對比重作日誌
LSN
號決定是否對該頁進行恢復數據。前面說的
checkpoint
也是有
LSN
號記錄的,
LSN
號串聯起一個事務開始到恢復的過程。
查看LSN: mysql> show engine innodb status\G;(其值由上減少) Log sequence number 2513682 --當前系統最大的LSN號 Log flushed up to 2513682 --當前已經寫入redo日誌文件的LSN Pages flushed up to 2513682 ---已經將更改寫入髒頁的lsn號 Last checkpoint at 2513673 --系統最後一次刷新buffer pool髒中頁數據到磁盤的checkpoint 以上4個LSN是遞減的,即: LSN1>=LSN2>=LSN3>=LSN4. |
檢查點(checkpoint,簡寫ckpt):就是落髒頁的點,本質是一個特殊的lsn編號。 檢查點的做用:1. 縮短數據庫恢復時間 2. 緩衝池不夠用的時候,刷新髒頁到磁盤 3. 重作日誌不夠用的時候,刷新髒頁. 解釋:當數據庫發生宕機的時候,數據庫不須要恢復全部的頁面,由於檢查點以前的頁面都已經刷新回磁盤了。故數據庫只須要對檢查點之後的日誌進行恢復,這就大大減小了恢復時間。緩衝池不夠用時,根據LRU算法,溢出最近最少使用的頁,若是頁爲髒頁,強制執行checkpoint,將頁刷新回磁盤。重作日誌不可用,是指,重作日誌的這部分不能夠被覆蓋,爲何?由於:這部分對應的數據還未刷新到磁盤上。重作日誌的設計是循環使用的。數據庫恢復時,若是不須要,便可被覆蓋;若是須要,必須強制執行checkpoint,將緩衝池中的頁至少刷新到當前重作日誌的位置。 檢查點的類型: 一種是sharp檢查點,一種是fuzzy檢查點。(fuzzy落盤部分髒頁,而sharp檢查點落盤全部髒頁。) fuzzy checkpoint在數據庫運行的時候,進行頁面的落盤操做,不過這種模式下,不是所有落盤,而是落盤一部分數據。 Fuzzy落盤的條件: 1. master thread checkpoint: master每一秒或者十秒落盤 2. sync check point: redo 不可用的時候,這時候刷新到磁盤是從髒頁鏈表中刷新的。 3. Flush_lru_list check point : 刷新flush list的時候 sharp checkpoint在數據庫關閉的時候將全部數據頁落髒。 sharp checkpoint落盤條件 1.關閉數據庫的時候設置 innodb_fast_shutdown=1,在關閉數據庫的時候,會刷新全部髒頁到數據庫內。 髒頁落盤的操做是異步的,所以不會阻塞其餘事務執行,而redo落盤的操做是同步的。 |
5.WAL
WAL(Write-Ahead Logging):日誌先行 日誌先行,任何對Innodb表的變更, redo log都要記錄對數據的修改,redo日誌就是記錄要修改後的數據。redo 日誌是保證事務一致性很是重要的手段,同時也可使在buffer pool修改的數據不須要在事務提交時馬上寫到磁盤上減小數據的IO從而提升整個系統的性能。這樣的技術推遲了buffer pool頁面的刷新,從而提高了數據庫的吞吐,有效的下降了訪問時延。帶來的問題是額外的寫redo log操做的開銷。而爲了保證數據的一致性,都要求WAL(Write Ahead Logging)。而redo 日誌也不是直接寫入文件,而是先寫入redo log buffer,而是批量寫入日誌。當須要將日誌刷新到磁盤時(如事務提交),將許多日誌一塊兒寫入磁盤。 |
Buffer Pool的每一個內存塊經過mmap的方式分配內存,在MySQL 5.7版本中開始默認以128M(可配置)的chunk單位分配內存塊,InnoDB存儲引擎中數據的訪問是按照頁(默認爲16KB)的方式從數據庫文件讀取到Buffer Pool中的,而後在內存中用一樣大小的內存空間來作一個映射。爲了提升數據訪問效率,數據庫系統預先就分配了不少這樣的空間,用來與文件中的數據進行交換,但實際並無被使用。用mmap分配的內存都是虛存,在top命令中佔用VIRT這一列,而不是RES這一列,只有相應的內存被真正使用到了,纔會被統計到RES中,提升內存使用率。 |
Buffer Pool的內存剛分配時,會被劃分紅若干對控制塊和緩存頁,InnoDB爲每個緩存頁都建立了一些所謂的控制信息,這些控制信息包括該頁所屬的表空間編號、頁號、頁在Buffer Pool中的地址,一些鎖信息以及LSN信息,固然還有一些別的控制信息,這些信息不須要記錄到磁盤,而是根據讀入數據塊在內存中的狀態動態生成的。每一個緩存頁對應的控制信息佔用的內存大小是相同的,咱們就把每一個頁對應的控制信息佔用的一塊內存稱爲一個控制塊吧,控制塊和緩存頁是一一對應的,它們都被存放到 Buffer Pool 中,其中控制塊都被存放到 Buffer Pool 的前邊,緩存頁都被存放到 Buffer Pool 後邊,在分配足夠多的控制塊和緩存頁後,可能剩餘的那點兒空間不夠一對控制塊和緩存頁的大小,天然就用不到了,這個用不到的那點兒內存空間就被稱爲碎片了。固然,若是把Buffer Pool的大小設置的剛恰好的話,也可能不會產生碎片。 |
1.1內存緩衝池:Buffer Pool
1.1.1爲何有內存緩衝池?
innodb做爲一個使用磁盤做爲持久化介質的數據庫,由於傳統磁盤的IO能力很是有限,在數據處理的過程當中,不可能全部的數據,都從磁盤中獲取,因此通常狀況,做爲關係型數據庫設計,都採用了內存緩衝池(Buffer Pool)做爲一種這種的手段,把最近經常使用的數據緩存到內存中,而後在特定的時間對內存和硬盤數據進行同步,來保證內存和硬盤數據的一致性。那麼在這種狀況下,其實磁盤和內存的交互瓶頸,就成爲了數據庫主要的瓶頸。緩衝池的設計目的爲了協調CPU速度與磁盤速度的鴻溝。
|
數據庫瓶頸說明:
關係型數據庫性能最大的瓶頸在硬盤上.大多數關係型數據庫的優化方向是在優化IO上. 優化IO主要從三個方面着手:1.減小隨機掃描,2減小硬盤IO請求次數.3.數據的整體的流量. |
buffer pool是一片連續的內存,緩衝池中緩存的數據頁類型有:索引頁、數據頁、undo頁、插入緩衝(insert buffer)、自適應哈希索引(adaptive hash index)、InnoDB存儲的鎖信息(lock info)、數據字典信息(data dictionary)等。 |
1.free page :此page未被使用,此種類型page位於free list中 2.clean page:此page被使用,對應數據文件中的一個頁面,可是頁面沒有被修改,此類型page位於lru list中 3.dirty page:此page被使用,對應數據文件中的一個頁面,可是頁面被修改過,沒有刷新到磁盤,此種類型page位於lru list和flush list中. 註明:free 類型的 page,必定位於 buf pool 的 free 鏈表中。clean,dirty 兩種類型的 page,必定位於 buf pool的 LRU 鏈表中;dirty page 還位於 buf pool 的 flush 鏈表中。 個人總結: free page數=free list節點數。dirty page數=flush list節點數。 dirty page數+clean page數=lru list節點數。 總page數=free page數+clean page數+dirty page數=free list節點數+lru list的節點數。 |
爲何有FREE list? Buffer Pool的內存剛分配時,會被劃分紅若干對控制塊和緩存頁。可是此時並無真實的磁盤頁被緩存到Buffer Pool中(由於尚未用到),以後隨着程序的運行,會不斷的有磁盤上的頁被緩存到Buffer Pool中,那麼問題來了,從磁盤上讀取一個頁到Buffer Pool中的時候該放到哪一個緩存頁的位置呢?或者說怎麼區分Buffer Pool中哪些緩存頁是空閒的,哪些已經被使用了呢?Free list就是用來記錄這些的。剛剛完成初始化的Buffer Pool中全部的緩存頁都是空閒的,因此每個緩存頁都會被加入到Free鏈表中。 free list記錄的信息:Free鏈表的節點中都記錄了某個緩存頁控制塊的地址,而每一個緩存頁控制塊都記錄着對應的緩存頁地址,因此至關於每一個Free鏈表節點都對應一個空閒的緩存頁。 原理: Free list其上的節點都是未被使用的節點,都是能夠當即使用的,若是須要從數據庫中分配新的數據頁,直接從上獲取便可。在使用的過程當中,每次成功load頁面到內存後,都會判斷free page是否夠用,若是不夠用的話,不然須要從FLU List或者LRU List淘汰必定的節點加入到free list中,這就能夠知足其餘進程在申請頁面,使系統可用。數據庫剛啓動的時候,LRU 列表爲空,當須要從磁盤中加載一個頁到Buffer Pool中時,就從Free鏈表中取一個空閒的緩存頁,而且把該緩存頁對應的控制塊的信息填上,而後把該緩存頁對應的Free鏈表節點從鏈表中移除,表示該緩存頁已經被使用了。而lru鏈表進行了清理動做,最後也須要把清理後的block加入到free纔算完成,維持頁數守恆。 (能夠將free list想象成n多個空的容器,能夠直接被使用,以備不時之需,但若是被使用,就給他貼上標籤,標識它裝的是什麼東西,而後將它踢出鏈表,當使用完畢,又從新加入free list)。 說明:Innodb_buffer_pool_wait_free:若是>0,說明出現性能負載,buffer pool free list中沒有可用塊 疑問:系統是怎麼判斷free list是否夠用的,free list的長度是怎麼定的? |
2.LRU List(最近最少使用算法least recently used)
內存遠比硬盤小,不可能將全部數據緩存到內存,故當buffer pool緩存滿後,再有請求時,就必須丟棄一部分不常常用的數據(冷數據)。LRU-list按數據頁的使用熱度來記錄數據頁位置(故其數據頁都被使用過),其兩端分別是熱數據組成的熱端和冷數據組成的冷端。該算法採用「中點插入法」:當插入一個新block時,移除表尾最近最少使用的block,在中點插入新block。這個中點將鏈表分爲兩部分:靠近表頭的一部分,爲young區,這裏的block是最近使用的節點,靠近表尾的一部分,爲old區,默認前5/8爲young list,存儲常常被使用的熱點page,後3/8爲old list(young:old=5:3)。當讀取的數據不在緩衝池裏的時候,讀取到的block須要插入到鏈表中,插入點爲中點(中點不是中間點,而是young與old的區分點),可是插入的新節點爲old區的節點,若是此時old區滿了得話,移除表尾的block,即新讀入的page默認被加在old-list頭。若是數據塊被用戶請求獲取,當即提高數據塊到young區的頭部(若是是innodb的read_head操做,延遲或不提高數據塊到NEW區的最前面)。當長期不使用的數據塊被擠到了Old list的尾巴,就會被系統回收。當讀取old區的block時,該節點將變成「young」節點,並且此節點移動到young區的表頭。從lru移除鏈表,要麼是非髒頁(也就是所謂的「clean的LRU鏈表節點」)按照策略進行「evict」,要是髒頁可是已經在flush鏈表中完成了刷新動做,能夠移除。LRU List還包含沒有被解壓的壓縮頁(這些壓縮頁剛從磁盤讀取出來,還沒來的及被解壓,innodb存儲引擎支持壓縮頁功能,非16k的頁經過unzip_LRU列表管理)。
總結:在數據庫操做中,被訪問的節點將移除到young的表頭,這樣一來,在young區中的未被訪問的節點將逐漸往表尾移動,當移動過中點,將變爲old區的節點。而old區的節點若被訪問到將變爲young節點移動到表頭,而old區中的未被訪問的節點依舊往表尾移動,當表滿時,表尾那個block將會被淘汰掉。
註明:1.innodb_old_blocks_pct:
肯定modpoint
位置,默認37
,(3/8=37%)
能夠經過這個調整young
與old
比.
2.innodb_old_blocks_time:
當有大的查詢時,可能會將熱點數據頁從LRU
列表中移除,爲了不這個問題能夠經過參數
innodb_old_blocks_time
的修改來實現,該參數表示頁讀取到
mid
位置後須要等待多久纔會被加入到
LRU
列表的熱端。
3.innodb_max_dirty_pages_pct:
這個參數據控制髒頁的比例(默認75%),即
當緩衝池中髒頁的數量佔據總頁數的75%時,也會強制進行Checkpoint,刷新一部分的髒頁到磁盤。
建議這個參數能夠設制到
75%-90%
都行。若是是大量寫入,而
且寫入的數據不是太活躍,能夠考慮把這個值設的低一點。
若是寫入或是更新的數據也就是熱數據就能夠考慮把這個值設爲:95%。
問題:lru list的長度是怎麼定的?
|
FLU鏈表是負責寫入數據塊的鏈表.即哪些塊該不應落盤和落盤的順序.鏈表中的全部節點都是髒頁,也就是說這些數據頁都被修改過,可是還沒來得及被刷新到磁盤上。在FLU List上的頁面必定在LRU List上,可是反之則不成立。一個數據頁可能會在不一樣的時刻被修改屢次,在數據頁上記錄了最老(也就是第一次)的一次修改的lsn,即oldest_modification。不一樣數據頁有不一樣的oldest_modification,FLU List中的節點按照oldest_modification排序,鏈表尾是最小的,也就是最先被修改的數據頁,當須要從FLU List中淘汰頁面時候,從鏈表尾部開始淘汰。加入FLU List,須要使用flush_list_mutex保護,因此能保證FLU List中節點的順序。數據庫經過checkpoint機制將髒頁刷新會磁盤,flush list中的頁即爲髒頁列表。 髒塊被刷入FLUSH鏈表,而後會在一段時間內進行落盤,當LRU List中的頁第一次被修改了,就將該頁的指針(page number)放入了Flush List(只要修改過,就放入,無論修改幾回)。Flush List 中包含髒頁(數據通過修改,可是未刷入磁盤的頁)。Flush list 中存放的不是一個頁,而是頁的指針(page number)。在 Buffer Pool 的每一個instance上都維持了一個flush list,flush list 上的 page 按照修改這些 page 的LSN號進行排序。所以按期作redo。checkpoint點時,選擇的 LSN 老是全部 bp instance 的 flush list 上最老的那個page(擁有最小的LSN)。因爲採用WAL的策略,每次事務提交時須要持久化 redo log 才能保證事務不丟。而延遲刷髒頁則起到了合併屢次修改的效果,避免頻繁寫數據文件形成的性能問題。 參數:innodb_io_capacity 和innodb_io_capacity_max 每次刷髒的page數。
|
4.lru和FLU鏈表的比較說明:
1.除了flush鏈表自己的flush操做能夠把dirty page從flush鏈表刪除外,lru鏈表的flush操做也會讓dirty page從flush鏈表刪除。 2.LRU list flush,由用戶線程觸發(MySQL 5.6.2以前);而Flush list flush由MySQL數據庫InnoDB存儲引擎後臺srv_master線程處理。(在MySQL 5.6.2以後,都被遷移到page cleaner線程中)。LRU list flush,因爲多是用戶線程發起,已經持有其餘的page latch(頁佔有),所以在LRU list flush中,不容許等待持有新的page latch,致使latch死鎖;而Flush list flush由後臺線程發起,未持有任何其餘page latch,所以能夠在flush時等待page latch。 3.LRU list flush,其寫出的dirty page,須要移動到LRU鏈表的尾部(MySQL 5.6.2以前版本);或者是直接從LRU鏈表中刪除,移動到free list(MySQL 5.6.2以後版本)。Flush list flush,不須要移動page在LRU鏈表中的位置。 4.LRU list flush,其目的是爲了寫出LRU 鏈表尾部的dirty page,釋放足夠的free pages,當buf pool滿的時候,用戶能夠當即得到空閒頁面,而不須要長時間等待;Flush list flush,其目的是推動Checkpoint LSN,使得InnoDB系統崩潰以後可以快速的恢復。 說明:Free鏈表跟LRU鏈表的關係是相互流通的,頁在這兩個鏈表間來回置換。而FLUSH鏈表記錄了髒頁數據,也是經過指針指向了LRU鏈表。 疑問:Free list 、lru list和flush list 增長與刪除節點的機制? |
5.查看buffer pool使用運行情況
mysql> show engine innodb status\G; ---不是當前狀態,而是過去某段時間範圍內的狀態。 ..... Buffer pool size 40955 Free buffers 40631 Database pages 324 Old database pages 0 Modified db pages 0 Pending reads 0 Pending writes: LRU 0, flush list 0, single page 0 Pages made young 0, not young 0 0.00 youngs/s, 0.00 non-youngs/s Pages read 287, created 37, written 55 0.00 reads/s, 0.00 creates/s, 0.00 writes/s No buffer pool page gets since the last printout Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s LRU len: 324, unzip_LRU len: 0 I/O sum[0]:cur[0], unzip sum[0]:cur[0] Buffer pool size:表示整個緩衝池中頁的數量。(Buffer pool size*16K/1024=buffer pool 大小) Free buffers表示free列表中頁的數量。 Database pages表示LRU列表中頁的數量,即正在被使用頁的數量 。 Modified db pages顯示了髒頁的數量。 buffer pool hit rate,緩衝區中讀到的頁 / 總共發出的讀頁數,表示緩衝命中率,通常不低於95%,若是偏低,要看看是否是有全表掃描形成LRU列表污染。 註明:緩存命中率: Innodb_buffer_pool_read_requests/(Innodb_buffer_pool_read_requests+Innodb_buffer_pool_reads) Pending reads 0 發出了請求但沒完成的io讀個數 Pending writes: LRU 0, flush list 0, single page 0 發出了請求但沒完成的io讀個數在各個列表上的體現 Pages read 287, created 37, written 55, 從磁盤上讀取出來的頁數, 在內存中創建了頁面可是沒從磁盤上讀取出來的頁面數以及寫入了的頁面數。 0.00 reads/s, 0.00 creates/s, 0.00 writes/s 在剛過去的時間間隔裏, 平均每秒的讀取數和新建數 上述中Buffer pool size = 40955正好爲Free buffers與Database pages之和。若不等,多是由於有自適應哈希索引、lock信息、insert buffer等頁。 髒頁比率 = 須要被flush的頁面數/(使用中的頁面數+空閒頁面數+1) 查看lru鏈表每一個頁的具體信息: mysql> select table_name, space,page_number,page_type from information_schema.innodb_buffer_page_lru where space=1; 查詢髒頁的數量: mysql> select table_name, space,page_number,page_type from information_schema.innodb_buffer_page_lru where oldest_modification>0; 查看buffer pool 運行情況: mysql> show status like 'Innodb_buffer_pool_%'; Innodb_buffer_pool_pages_data 分配出去,正在被使用頁的數量,即lru鏈表中的page數(clean+dirty) Innodb_buffer_pool_pages_dirty 髒頁但沒被flush除去的頁面數,即flush list中的page數 Innodb_buffer_pool_pages_flushed 已經flush的頁面數 Innodb_buffer_pool_pages_free 當前空閒頁面數,即free list中page數。 Innodb_buffer_pool_pages_latched 當前被鎖住的頁面數 Innodb_buffer_pool_pages_misc 用於管理功能的頁面數, 如adaptive hash等,其值爲Innodb_buffer_pool_pages_total - Innodb_buffer_pool_pages_free - Innodb_buffer_pool_pages_data Innodb_buffer_pool_pages_total 緩衝區總共的頁面數 Innodb_buffer_pool_read_ahead_rnd 隨機預讀的次數 Innodb_buffer_pool_read_ahead_seq 線性預讀的次數 Innodb_buffer_pool_read_requests 從內存中邏輯讀取的請求數 Innodb_buffer_pool_reads 從磁盤上一頁一頁的讀取的頁數 Innodb_buffer_pool_wait_free 緩衝池等待空閒頁的次數,當須要空閒塊而系統中沒有時,就會等待空閒頁面,此值應該很小。若是大於0,則表示InnoDb緩衝池過小。 Innodb_buffer_pool_write_requests 緩衝池總共發出的寫請求次數 Innodb_data_fsyncs 總共完成的fsync次數 Innodb_data_pending_fsyncs innodb當前等待的fsync次數 Innodb_data_pending_reads innodb當前等待的讀的次數 Innodb_data_pending_writes innodb當前等待的寫的次數 Innodb_data_read 總共讀入的字節數 Innodb_data_reads innodb完成的讀的次數 Innodb_data_writes innodb完成的寫的次數 Innodb_data_written 總共寫出的字節數 緩衝池命中率 = (Innodb_buffer_pool_read_requests)/(Innodb_buffer_pool_read_requests + Innodb_buffer_pool_read_ahead + Innodb_buffer_pool_reads) 平均每次讀取的字節數 = Innodb_data_read/Innodb_data_reads |
default_storage_engine(默認存儲引擎) innodb_data_file_path(ibdata1的文件大小及自增) innodb_buffer_pool_size(緩存池大小) innodb_buffer_pool_instances(緩存池個數) innodb_additional_mem_pool_size(額外內存池的大小) innodb_file_per_table(是否開啓獨立表空間) innodb_buffer_pool_chunk_size(在線修改) |
1.innodb_buffer_pool_size大小設置
innodb_buffer_pool_size:若是系統總內存比較小,就設置50% ,若是內存大,最大可設置75%左右,其並非mysql佔用總內存。 舉例: OS內存與buffer_pool :8GB -->4GB 16G -->12GB 32G --->20GB 64G --->50GB 緩衝池的大小,直接影響了數據庫的性能,經過增長緩衝池的大小,能夠提高數據庫的性能。 show global status like 'Innodb_buffer_pool_pages_data';--lru鏈表中頁的數量(clean+dirty) show global status like 'Innodb_buffer_pool_pages_total'; --buffer pool中總頁數 show global status like 'Innodb_page_size'; --頁大小,默認16KB。 計算Innodb_buffer_pool_pages_data/Innodb_buffer_pool_pages_total*100% 當結果 > 95% 則增長 innodb_buffer_pool_size, 建議使用物理內存的 75% 當結果 < 95% 則減小 innodb_buffer_pool_size, 建議設置大小爲: Innodb_buffer_pool_pages_data* Innodb_page_size * 1.05 / (1024*1024*1024) 何時調整innodb_buffer_pool_size合適? 調大:命令: show status like 'Innodb_buffer_pool_%'; 算法: InnoDB buffer pool 命中率 = innodb_buffer_pool_read_requests / (innodb_buffer_pool_read_requests + innodb_buffer_pool_reads ) * 100 當其值低於99%則可適當調大innodb_buffer_pool_size。 調小:命令:show engine innodb status\G;Free buffers :表示有多少空閒buffer。若是 此值長時間都較高,則能夠考慮減少InnoDB緩衝池大小。 註明: 1. innodb_buffer_pool_size大小是分配給全部的buffer pools。每一個buffer pool 實例至少1GB。 2. innodb_buffer_pool_size = N * (innodb_buffer_pool_chunk_size * innodb_buffer_pool_instances) 其中N爲正整數。 3.設置的過大,會致使system的swap空間被佔用,致使操做系統變慢,從而減低sql查詢的效率。 |
2.innodb_buffer_pool_instances大小設置
參數innodb_buffer_pool_instances設置buffer_pool實例的個數, 默認爲 8。 說明: 1.每一個buffer_pool_instance無競爭關係: 每一個buffer_pool_instance都有本身的鎖,信號量,物理塊(Buffer chunks)以及邏輯鏈表(下面的各類List),即各個instance之間沒有競爭關係,能夠併發讀取與寫入。全部instance的物理塊(Buffer chunks)在數據庫啓動的時候被分配,直到數據庫關閉內存才予以釋放。 2.當innodb_buffer_pool_size小於1GB時候,innodb_buffer_pool_instances被重置爲1,主要是防止有太多小的instance從而致使性能問題。 3.每一個Buffer Pool Instance有一個page hash鏈表,經過它,使用space_id和page_no就能快速找到已經被讀入內存的數據頁,而不用線性遍歷LRU List去查找。注意這個hash表不是InnoDB的自適應哈希,自適應哈希是爲了減小Btree的掃描,而page hash是爲了不掃描LRU List。 4.每一個buffer_pool實例都有對應的buffer_pool,多個buffer pool實例的目的,是減小內存的對於一個鏈表的栓鎖徵用,對性能無明顯的提高。 5.innodb_buffer_pool_instances大小設置: 建議:若是內存2GB,配1個innodb_buffer_pool_instances 便可;4GB-8GB內存配2個,16-32GB內存配4個,64GB及以上配8個左右,通常不超過8個. |
在mysql5.6裏要修改innodb_buffer_pool大小隻能停庫後修改配置文件再啓動.但在5.7裏能夠在線修改buffer_pool. 參數:innodb_buffer_pool_chunk_size 默認 128MB,read-only。 mysql> show variables like '%buffer_pool_chunk_size%'; Variable_name Value innodb_buffer_pool_chunk_size 134217728 ---134217728/1024/1024=128 報告在線調整緩衝池大小操做的狀態: mysql> show status like '%Innodb_buffer_pool_resize_status%'; 註明:在線修改大小,就是咱們無論數據庫的狀況下,調整buffer pool size大小,可是調整的大小,必須是innodb_buffer_pool_chunk_size* innodb_buffer_pool_instances的整數倍,若不是,則自動調整爲其倍數值,在錯誤日誌裏有顯示。 |
開啓獨立表空間,建議開啓,開啓後做用: 1. 每一個表都有自已獨立的表空間。 2. 每一個表的數據和索引都會存在自已的表空間中。 3. 能夠實現單表在不一樣的數據庫中移動。 4. 空間能夠回收 啓用innodb_file_per_table後,每張表的表空間只存放本身的:數據,索引和插入緩衝BITMAP頁。其它信息仍放在默認表空間。其它信息如:回滾(undo)信息、插入緩衝索引頁、系統的事物信息、二次寫緩衝(Double write buffer)等 |
數據預熱的做用:當數據庫重啓,則剛開啓階段須要將數據從硬盤加載到buffer pool中,走物理IO,致使數據庫性能較差,有了數據預熱,則在數據庫重啓過程當中會將熱數據寫到硬盤的另外一塊地方,數據庫開啓後則會加載到buffer pool中。其中ib_buffer_pool爲存放數據預熱信息的文件.
[root@lbg mysql3306]# ll ib_buffer_pool
-rw-r----- 1 mysql mysql 615 Oct 15 23:33 ib_buffer_pool
自動數據預熱:
innodb_buffer_pool_dump_pct=40 --LRU上最熱的page的百分⽐.(默認40%) innodb_buffer_pool_dump_at_shutdown = 1 --在關閉時把熱數據dump到本地磁盤。(5.7.7之後默認是on) innodb_buffer_pool_load_at_startup = 1 ---在啓動時把熱數據加載到內存。(默認關閉,最好開啓) 手工開啓數據預熱: innodb_buffer_pool_dump_now = 1 ----採用手工方式把熱數據dump到本地磁盤。(默認關閉) innodb_buffer_pool_load_now = 1 ---採用手工方式把熱數據加載到內存。(默認關閉) 問題:手動數據預熱的方法? |
innodb_lock_wait_timeout 事務等待獲取資源等待的最長時間,超過這個時間還未分配到資源則會返回應用失敗; innodb_autoextend_increment: 系統表空間文件每次擴展的大小 |
刷新臨階頁的做用:當刷新一個髒頁時,innodb會檢測該頁所在區(extent)的全部頁,若是是髒頁,那麼一塊兒進行刷新,達到合併IO,隨機轉順序的優化。 參數1:innodb_flush_neighbors={0|1|2} (>=MySQL 5.6) 0:表示關閉該功能 1:表示刷新一個區內的髒頁 2:表示刷新幾個連續的髒頁 參數2:show variables like '%innodb_flush_method%'; --直接設置其值爲O_DIRECT便可. 做用:設置innodb在落盤髒頁的時候,繞過操做系統緩存,直接落盤,提升效率. mysql> show variables like '%flush_method%'; +---------------------+----------+ | Variable_name | Value | +---------------------+----------+ | innodb_flush_method | O_DIRECT | +---------------------+----------+ 建議: 若是是機械硬盤的話,建議使用2.,建議打開該特性,用來提升落盤效率 若是固態硬盤,關閉掉該特性0 (SSD建議關閉此功能) |
8 insert buffer(插入緩衝)
插入緩衝 insert buffer 又稱change buffer。位於buffer pool中,從MySQL5.5版本開始,Insert buffer改名爲change buffer,除了緩衝對二級索引的insert操做,還包括update/delete/後臺purge操做。 插入緩衝的做用:由於當修改表數據時,不只要修改原表數據,還要修改輔助索引的數據,額外開銷太大。插入緩衝是針對輔助索引的優化手段.對於輔助索引的插入或者更新操做,不是每一次直接插入到索引頁中,而是先判斷輔助索引頁是否在內存中,若是沒有的話,那麼要插入到一個insert buffer頁中,而後在達到一個時間點後,進行insert buffer和輔助索引的葉子節點的合併,這樣能夠將多個插入操做合併到一個插入操做中,節約大量的IO請求。數據庫使用插入緩衝的條件: 1. 索引是輔助索引 2. 索引不是惟一索引.由於在合併插入緩衝的過程當中,數據庫並不去判斷惟一性. 3.索引必須在硬盤上,不在內存中.(若在內存上,直接合並便可,不必使用insert-buffer) 使用insert buffer過程:1. 在沒有Insert/ChangeBuffer時,每次插入一條記錄,就要讀取一次頁(讀取內存,或者從磁盤讀到內存),而後將記錄插入到頁中; 2. 在有Insert/ChangeBuffer時,當插入一條記錄時,先判斷記錄對應要插入的二級索引(secondaryindex)頁是否在BufferPool中: 3. 若是該二級索引(secondaryindex)頁已 在Buffer Pool中,則直接插入; 4. 若是沒有在內存中,先將其Cache起來,放到Insert/ChangeBuffer中,等到該二級索引(secondaryindex)頁被讀到時(或主線程每1s或10s時),將Insert/ChangeBuffer中該頁對應的記錄合併(Merge)進去,從而減小I/O操做; insert buffer的優勢:1. 減小磁盤的離散讀取 2. 將屢次插入合併成一次操做(配合異步IO) insert buffer的合併時機:1. 經過master thread 按期進行合併(每1s或10s) 2. 用戶在讀取輔助索引的時候進行合併 Insert Buffer參數設置:innodb_change_buffering = all All ----默認,表示全部 none (禁用) inserts --只優化insert. Deletes--只優化delete. changes =(insert & delete-marking) --優化insert+delete-marking purge--只優化purge操做 |
double-write的做用:解決部分寫的問題.double write的實現機制:Double write分爲兩部分:一部分是內存中的double write buffer ,大小爲2MB(16k一個頁,一共128個頁),不屬於buffer pool。第二部分是磁盤共享表空間(即ibdata1)連續的128個頁,即2個區(extend),大小一樣爲2M,在對髒頁進行落盤的時候,並非直接進行落盤,而是先複製到double write buffer,而後再分別寫入到共享表空間(ibdata1)(這是順序IO),而後髒頁再寫入本身的表空間( .ibd文件)。 頁面的刷新會遇到部分寫的問題,也就是說對於只寫了其中一個頁面,只寫了一部分的內容,innodb的頁面大小是16KB,可是寫入過程當中只寫了4KB(操做系統僅僅保證512字節寫入的完整性),這個是時候由於頁面不是完整的,所以不能經過redo來進行恢復。redo恢復的前提條件是頁是完整的。在數據庫崩潰後,傳統的數據庫會使用redo log進行恢復,恢復的原理是經過redo對數據從新進行物理操做,可是若是這個數據頁自己發生了損壞,那麼redo對其進行重作也是沒有做用的,innodb的double-write,在寫入的時候,創造了一個關於頁的副本,這樣即便在發生寫失效後,也能夠經過副本頁,對還原重作。故double-write是針對最近需落盤的髒頁(2M)先在內存生成其鏡像塊,而後該鏡像塊落盤到ibdata1文件中的double-write中(2M).最後髒頁才落盤. 說明:若Double-write落盤時,發生部分寫,那麼源數據塊依舊是無缺的,沒有發生改變,故依舊可根據源數據塊和redo進行數據恢復。若髒頁落盤發生部分寫,那麼能夠根據double-write和redo進行恢復,若沒有double-write,則源數據塊損壞無法恢復,則就是double-write的意義所在。 注:Double-write增長了IO次數,mysql性能可能會下降10%. 開啓關閉double_write參數: innodb_doublewrite 問題:double_write落盤機制?能夠在redo落盤前落盤嗎? |
adaptive_hash_index的做用: 自適應hash索引: hash索引對那些常常訪問的索引頁建立,可視爲創建在B+tree索引上的「索引」。 維護索引葉頁面中全部記錄的索引鍵值(或鍵值前綴)到索引葉頁面位置的Hash映射關係,可以根據索引鍵值(前綴)快速定位到葉頁面知足條件記錄的Offset,減小了B+樹Search Path的代價,將B+樹從Root頁面至Leaf頁面的路徑定位,優化爲Hash Index的快速查詢。hash索引只在buffer pool中,不落盤。數據庫自動發現熱數據並對熱數據建立hash索引(不能人爲干預)。 開啓關閉自適應hash索引參數: innodb_adaptive_hash_index AHI的要求: 1.以該模式訪問了100次該數據頁。(訪問模式同樣指的是查詢的條件同樣) 2.頁經過該模式訪問了N次,其中N=頁中記錄*1/16; 若是一張表幾乎整個被至於主內存中,那麼有了哈希索引就能夠直接查找任意元素並將其索引值轉換爲一系列的指針從而提高查詢速度。InnoDB有一個機制能夠監控索引的搜索。若是InnoDB注意到查詢能夠經過創建哈希索引獲得優化,那麼他就會自動作這件事。在一些負載的狀況下,hash index的查找效益明顯高於監控索引查詢和維護hash index結構的花費。 但有時候,確保ahi訪問的讀寫鎖卻會在負載很重的狀況下變成競爭來源。好比不少併發關聯。like操做符,和%匹配符不能再ahi中獲益,在這種狀況下能夠關閉ahi,hash索引老是在基於已存在的b-tree索引的結構上建立,hash index能夠是部分的覆蓋常常訪問的頁。可使用 SHOW ENGINE INNODB STATUS 命令去監控,若是看到了不少線程在等待 RW-latch競爭,那麼能夠考慮關閉該功能。從MySQL 5.7開始,自適應哈希索引搜索系統是分區的。每一個索引都會綁定到一個特殊的分區上,而且每一個分區都由各自獨立的鎖存器來保護。分區受到innodb_adaptive_hash_index_parts配置項的控制。在MySQL5.7以前,自適應哈希索引搜索系統是經過一個單獨的鎖存器來保護,在高負載的狀況下它會變成競爭點。innodb_adaptive_hash_index_parts選項默認值爲8,最大值爲512。 說明:AHI啓動後,讀寫速度提升了2倍,輔助索引的鏈接操做性能能夠提升5倍。 |
2.1.1 InnoDB Log Buffer(日誌緩衝區)和undo介紹
1.爲何設計redo系統?
1.每次修改數據塊落盤,哪怕修改一條數據,都要落盤,IO壓力太大,並且數據塊落盤是隨機IO,效率過低.若是commit落盤的是髒塊,髒塊的落盤對硬盤的IO產生了很是大的性能影響.因此設置redo,只記錄數據頁的修改偏移狀況,減小IO的數據量.(redo---記錄的是偏移量,故原值必須存在,纔可恢復數據正確性.) 2.數據塊落盤是隨機落盤,redo落盤是順序IO,redo數據塊和硬盤塊都是512字節,相契合,效率更高. |
2.commit的實際意義.
數據庫commit成功是保證了redo的落盤,不保證數據塊的落盤.redo的落盤就已保證了數據事務的安全性. |
3.redo的日誌類型(物理邏輯日誌)
redo屬於物理邏輯日誌,物理性體如今redo記錄的是數據頁的改變.邏輯性體如今redo記錄的是數據頁修改的偏移量. Redo只記錄DML操做致使的頁面變化,不記錄DDL操做. |
4.redo落盤時間(同步IO)
1.InnoDB Log Buffer滿1/2. 2. 1s和10s自動落盤redo. 3.commit時,必須落盤redo. 說明:redo落盤是同步IO,且是順序IO,redo數據塊大小是512字節而非16KB。 |
5.redo日誌文件寫入方式
redo log文件以ib_logfile[number]命名,日誌目錄能夠經過參數innodb_log_group_home_dir控制。redo log 以順序的方式寫入文件文件,寫滿時則回溯到第一個文件,進行覆蓋寫。Redo log文件是循環寫入的,在覆蓋寫以前,老是要保證對應的髒頁已經刷到了磁盤。在很是大的負載下,Redo log可能產生的速度很是快,致使頻繁的刷髒操做,進而致使性能降低,一般在未作checkpoint的日誌超過文件總大小的76%以後,InnoDB 認爲這多是個不安全的點,會強制的preflush髒頁,致使大量用戶線程stall住。若是可預期會有這樣的場景,咱們建議調大redo log文件的大小。能夠作一次乾淨的shutdown,而後修改Redo log配置,重啓實例。 1.噹噹前未刷髒的最老lsn和當前lsn的距離超過max_modified_age_async(71%)時,且開啓了選項innodb_adaptive_flushing時,page cleaner線程會去嘗試作更多的dirty page flush工做,避免髒頁堆積。 2.噹噹前未刷髒的最老lsn和當前Lsn的距離超過max_modified_age_sync(76%)時,用戶線程須要去作同步刷髒,這是一個性能降低的臨界點,會極大的影響總體吞吐量和響應時間。 3.當上次checkpoint的lsn和當前lsn超過max_checkpoint_age(81%),用戶線程須要同步地作一次checkpoint,須要等待checkpoint寫入完成。 4.當上次checkpoint的lsn和當前lsn的距離超過max_checkpoint_age_async(78%)但小於max_checkpoint_age(81%)時,用戶線程作一次異步checkpoint(後臺異步線程執行CHECKPOINT信息寫入操做),無需等待checkpoint完成。 [root@lbg mysql3306]# ll ib_logfile* -rw-r----- 1 mysql mysql 268435456 Oct 16 10:35 ib_logfile0 -rw-r----- 1 mysql mysql 268435456 Oct 12 16:18 ib_logfile1 註明: InnoDB 日誌組的特性已經被廢棄(redo日誌寫多份),歸檔日誌(InnoDB archive log)特性也在5.7被完全移除了。 |
6.redo文件和redo塊結構
redo文件結構: 每一個日誌文件的前2048字節是存放的文件頭信息。頭結構定義在」storage/innobase/include/log0log.h」 中。 1.LOG_GROUP_ID 這個log文件所屬的日誌組,佔用4個字節,當前都是0 2. LOG_FILE_START_LSN 這個log文件記錄的開始日誌的lsn,佔用8個字節 3. LOG_FILE_WAS_CRATED_BY_HOT_BACKUP 備份程序所佔用的字節數,共佔用32字節 4. LOG_CHECKPOINT_1/LOG_CHECKPOINT_2 兩個記錄InnoDB checkpoint信息的字段,分別從文件頭的第二個和第四個block開始記錄,只使用日誌文件組的第一個日誌文件。 從地址2KB偏移量開始,其後就是順序寫入的各個日誌塊(log block)。 REDO數據塊結構: 在InnoDB存儲引擎中,重作日誌都是以512字節進行存儲的,這意味着重作日誌緩存、重作日誌文件塊都是以塊block的方式進行保存的,稱爲重作日誌塊(redo log block)每塊的大小512字節。每一個日誌塊包含一個日誌頭段(12字節)、一個尾段(4字節),以及一組日誌記錄(512 – 12 – 4 = 496字節) 。 |
7.redo相關參數
innodb_log_buffer_size --redo buffer大小。默認8M。 innodb_log_files_in_group ---redo log文件個數,默認2個。 innodb_log_file_size ---每一個文件的大小。默認值:5242880 (5M)。 innodb_log_files_in_group * innodb_log_file_size ---總的redo log大小。 innodb_flush_log_at_trx_commit ---落盤機制。 |
8.redo文件大小設置
參數:innodb_log_file_size 配置redo文件大小。 內存<1G: 48M 內存<=4G: 128M 內存<=8G: 512M 內存<=16G: 1024M |
9.redo buffer大小設置
參數:innodb_log_buffer_size 配置redo buffer大小。 日誌緩衝的大小,重作日誌緩衝,通常狀況下8MB足夠使用,若是不夠放心,可使用16MB。每滿1/2就強制落盤,故其無需設置太大。 |
10.redo落盤參數(innodb_flush_log_at_trx_commit)
innodb_flush_log_at_trx_commit:這個參數有三個值能夠設置0或1或2. 0 :redo buffer每秒寫入redo log file一次(數據庫),而且log-file的磁盤flush刷新同步進行(系統),這種狀況下,log buffer僅僅在master thread的每秒循環中執行。(每秒落盤。) 1 每次事務提交都會進行log buffer的寫入log file(數據庫),而且flush到磁盤中。(每次commit落盤。) 2 每次事務提交都會進行log buffer的寫入到log file(數據庫),可是flush操做是每秒進行一次。(每次commit寫到操做系統緩存,但每秒落盤一次。) 說明: 設置爲0的時候,速度最快,可是不安全。mysqld進程崩潰後,致使上一秒的數據所有丟失。 設置爲1的時候,會形成一個事務的丟失。 設置爲2的時候,速度較快,數據庫崩潰會形成某個事務丟失,可是不會丟失一秒的數據,只有當服務器宕機或者斷電纔會形成1s的數據丟失。 注:這個參數配合sync_binlog(使binlog在每N次binlog寫入後與硬盤 同步),共同組成了innodb的日誌刷盤策略和數據安全性。至關重要當兩個參數都爲1的時候,速度最慢,可是數據最安全。(雙1策略) 注:通常的髒頁落盤都是先從mysqld的內存寫到操做系統緩存,再從操做系統緩存寫入磁盤。 |
undo介紹:
1.undo日誌做用:
Undo做用:1.保證rollback(事務的回滾). 2.mvcc(多版本併發控制) Undo記錄中存儲的是老版本數據,當一箇舊的事務須要讀取數據時,爲了能讀取到老版本的數據,須要順着undo鏈找到知足其可見性的記錄。當版本鏈很長時,一般能夠認爲這是個比較耗時的操做.大多數對數據的變動操做包括INSERT/DELETE/UPDATE,其中INSERT操做在事務提交前只對當前事務可見,所以產生的Undo日誌能夠在事務提交後直接刪除(誰會對剛插入的數據有可見性需求呢!!),而對於UPDATE/DELETE則須要維護多版本信息,在InnoDB裏,UPDATE和DELETE操做產生的Undo日誌被歸成一類,即update_undo。爲了保證事務併發操做時,在寫各自的undo log時不產生衝突,InnoDB採用回滾段的方式來維護undo log的併發寫入和持久化。回滾段其實是一種 Undo 文件組織方式,每一個回滾段又有多個undo log slot。 |
2.undo日誌類型及記錄時機
Undo是邏輯日誌.undo頁存放在buffer pool中,記錄undo日誌的時機: 1. DML操做致使的數據記錄變化,均須要將記錄的前鏡像寫入Undo日誌(邏輯日誌) 2.Undo頁面的修改,一樣須要記錄Redo日誌; 3. Rollback--反向使用事務的全部Undo日誌,回滾整個事務所作的修改; 不一樣的update語句,寫的日誌量有較大的差別(三種update狀況) 1. in place update 日誌量最小,操做最簡單 2. 不修改主鍵列,日誌量其次 3. 修改主鍵列,日誌量最大,操做最複雜 |
3.undo文件(最少2個。)
undo日誌最先放在系統表空間ibdata1裏.但ibdata1只能擴大不能縮小.在mysql5.6及以上版本是放在獨立表空間裏. UNDO的undo段的設置: 1. rseg0預留在系統表空間ibdata中; 2. rseg 1~rseg 32這32個回滾段存放於臨時表的系統表空間中; 3. rseg33~ 則根據配置存放到獨立undo表空間中(若是沒有打開獨立Undo表空間,則存放於ibdata中) [root@lbg mysql3306]# ll undo* -rw-r----- 1 mysql mysql 10485760 Oct 15 21:53 undo001 -rw-r----- 1 mysql mysql 10485760 Oct 15 21:53 undo002 -rw-r----- 1 mysql mysql 10485760 Oct 15 21:09 undo003 |
4.在線回收undo表空間功能.
Mysql5.6中undo表空間獨立了,5.7中增長了在線回收undo表空間功能. innodb_undo_directory = /home/mysql3306/mysql3306/ ----配置undo目錄 innodb_undo_logs = 128 #must >=35.default 128 innodb_undo_tablespaces = 3 #must >=2 ---undo文件個數(必須大於2) innodb_undo_log_truncate = 1 -----開啓在線回收功能.(5.7默認關閉,8.0默認開啓) innodb_max_undo_log_size = 1000M ----undo單個文件最大值,即回收閥值. innodb_purge_rseg_truncate_frequency = 128 |
5.inset/update/delete的redo和undo過程
1.insert的redo和undo過程. 第一步:寫undo的redo. 第二步:寫undo. 第三步:寫入數據頁(insert in memory page) 第四步:寫聚簇索引和輔助索引變化的redo. 第五步: 刷新髒頁. 2.delete的redo過程.(沒有修改主鍵列)第一步:寫undo的redo. 第二步:寫undo. 第三步:修改數據頁((insert in memory page)) 第四步:寫redo.(write del mark redo,在聚簇索引和輔助索引打上刪除標記的redo) 第五步: 刷新髒頁.(oracle裏delete只是打上刪除標記,表空間不會釋放.) 3.update(不修改主鍵列和修改主鍵列,先後項長度變不變)第一步:寫undo的redo. 第二步:寫undo. 第三步:修改數據頁((insert in memory page)) 第四步:寫redo.(write insert redo,包括聚簇索引和輔助索引) 第五步: 刷新髒頁. 若不修改主鍵列,若空間夠用,能夠直接在原位置修改. 若空間不夠用,則打上刪除標記,從新插入.若修改了主鍵列,則會打上刪除標記,而後從新插入數據. |
innodb_additional_mem_pool_size:設置innodb額外內存池( InnoDB Additional Memory Pool)的大小.若是數據字典,以及內部數據結構緩存,若是表數量特別多的話,那麼須要的內存就越大,默認8MB,通常設置8MB-32MB足夠使用,通常設置16MB足夠。若是咱們經過 innodb_additional_mem_pool_size 參數所設置的內存大小不夠,InnoDB 會自動申請更多的內存,並在 MySQL 的 Error Log 中記錄警告信息。 註明:在mysql5.7上取消了InnoDB Additional Memory Pool。 |
4.1 MyISAM索引緩存 Key Buffer(key_buffer_size)
MyISAM 索引緩存將MyISAM表的索引信息(.MYI文件)緩存在內存中,以提升其訪問性能。這個緩存能夠說是影響MyISAM存儲引擎性能的最重要因素之一了,經過 key_buffere_size 設置可使用的最大內存空間。 注意:即便運行一個所有采用innodb的模式,仍須要定義一個索引碼緩衝區,由於MYSQL元信息與MyISAM定義相同。 參數:key_buffer_size ---Global 動態,默認 8M 推薦配置:默認 8M # 若是爲 MyISAM 表的話,設置 key_buffer 爲內存的 5 - 50 % , # 可是對於 InnoDB 來講,必須保證 key_buffer+ InnoDB 緩衝池小於內存的 80%。 如何確認key_buffer_size不夠用? 查看show full processlist的State列中,值Repairing the keycache是一個明顯的指標,它指出當前索引碼緩衝區大小不足以執行當前運行的SQL語句。這將致使額外的磁盤I/O開銷。 |
4.2 查詢緩存 Query Cache (query_cache_size):
當打開MySQL的Query Cache以後,MySQL接收到每個SELECT類型的Query以後都會首先經過固定的Hash算法獲得該Query的Hash值,而後到Query Cache中查找是否有對應的Query Cache。若是有,則直接將Cache的結果集返回給客戶端。若是沒有,再進行後續操做,獲得對應的結果集以後將該結果集緩存到Query Cache中,再返回給客戶端。當任何一個表的數據發生任何變化以後,與該表相關的全部Query Cache所有會失效,因此Query Cache對變動比較頻繁的表並非很是適用,但對那些變動較少的表是很是合適的,能夠極大程度的提升查詢效率,如那些靜態資源表,配置表等等。 參數說明: 爲了儘量高效的利用Query Cache,MySQL針對Query Cache設計了多個query_cache_type值和兩個QueryHint:SQL_CACHE和SQL_NO_CACHE。當query_cache_type設置爲0(或者 OFF)的時候不使用Query Cache,當設置爲1(或者 ON)的時候,當且僅當Query中使用了SQL_NO_CACHE 的時候MySQL會忽略Query Cache,當query_cache_type設置爲2(或者DEMAND)的時候,當且僅當Query中使用了SQL_CACHE提示以後,MySQL纔會針對該Query使用Query Cache。能夠經過query_cache_size來設置可使用的最大內存空間。 參數 query_cache_size: Global Dynamic,Default 0 推薦配置:16M 如何肯定系統query cache的狀況? show global status like 'qcache%'; 或者 select * from information_schema.GLOBAL_STATUS where VARIABLE_NAME like 'Qcache%'; 公式:(Qcache_hits/Qcache_hits+Com_select+1)*100來肯定查詢緩存的有效性 mysql> show variables like 'Query_cache_size'; mysql> show global status like 'Com_select'; mysql> show global status like 'Qcache%'; |
4.3鏈接線程緩存 Thread Cache(thread_cache_size)
鏈接線程是MySQL爲了提升建立鏈接線程的效率,將部分空閒的鏈接線程保持在一個緩存區以備新進鏈接請求的時候使用,這尤爲對那些使用短鏈接的應用程序來講能夠極大的提升建立鏈接的效率。 參數:thread_cache_size,Global,Dynamic,Default 0 建議配置: 1G —> 8; 2G —> 16; 3G —> 32; >3G —> 64 注意,這裏設置的是能夠緩存的鏈接線程的數目,而不是內存空間的大小。 如何肯定系統Thread Cache的狀況? mysql> show global status like 'Threads_created'; mysql> show global status like 'connections'; Threads_cached :表明當前此時此刻線程緩存中有多少空閒線程。 Threads_connected :表明當前已創建鏈接的數量,由於一個鏈接就須要一個線程,因此也能夠當作當前被使用的線程數。最好將thread_cache_size設置成與threads_connected同樣。 Threads_created :表明從最近一次服務啓動,已建立線程的數量。 Threads_running :表明當前激活的(非睡眠狀態)線程數。並非表明正在使用的線程數,有時候鏈接已創建,可是鏈接處於sleep狀態,這裏相對應的線程也是sleep狀態。 鏈接線程緩存的命中率: (Connections - Threads_created) / Connections * 100% 計算出鏈接線程緩存的命中率。 |
4.4 表緩存 Table Cache(table_open_cache)
做用:表緩存區主要用來緩存表文件的文件句柄信息,當咱們的客戶端程序提交Query給MySQL的時候,MySQL須要對Query所涉及到的每個表都取得一個表文件句柄信息,若是沒有Table Cache,那麼MySQL就不得不頻繁的進行打開關閉文件操做,無疑會對系統性能產生必定的影響,Table Cache 正是爲了解決這一問題而產生的。在有了Table Cache以後,MySQL每次須要獲取某個表文件的句柄信息的時候,首先會到Table Cache中查找是否存在空閒狀態的表文件句柄。若是有,則取出直接使用,沒有的話就只能進行打開文件操做得到文件句柄信息。在使用完以後,MySQL會將該文件句柄信息再放回Table Cache 池中,以供其餘線程使用。 在MySQL5.1.3以前的版本經過table_cache參數設置,但從MySQL5.1.3開始改成table_open_cache來設置其大小。 參數:table_open_cache ---Global,Dynamic,Default 400 注意,這裏設置的是能夠緩存的表文件句柄信息的數目,而不是內存空間的大小。 推薦配置:根據內存配置4G--->2048 大於最大Opened_tables。 在mysql默認安裝狀況下,table_cache的值在2G內存如下的機器中的值默認時256到 512,若是機器有4G內存,則默認這個值是2048。(可能不對) 查看open_tables和opened_teables值: mysql> show global status like 'open%_tables'; 如何肯定系統table_open_cache的狀況? mysql> show variables like 'table_open_cache'; 對於大多數狀況,比較適合的值: Open_tables / Opened_tables >= 0.85 Open_tables / table_cache <= 0.95 |
4.5表定義信息緩存 Table definition Cache (table_definition_cache)
表定義信息緩存是從 MySQL5.1.3 版本纔開始引入的一個新的緩存區,用來存放表定義信息。當MySQL 中使用了較多的表的時候,此緩存無疑會提升對錶定義信息的訪問效率。MySQL提供了table_definition_cache 參數給咱們設置能夠緩存的表的數量。注意,這裏設置的是能夠緩存的表定義信息的數目,而不是內存空間的大小。 參數:table_definition_cache -----Global, Dynamic, Default 400 推薦配置:根據內存配置4G 2048 和Table Cache同樣便可 |