18、MySQL內存體系架構及參數總結


內存結構:
Mysql 內存分配規則是:用多少給多少,最高到配置的值,不是立即分配
圖只做大概參考
全局緩存包括:
global buffer(全局內存分配總和) =
   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                                -- 查詢高速緩存,緩存查詢結果,提高反復查詢返回效率
+thread_cache_size                                       -- Thread_Cache 中存放的最大連接線程數
+table_cahce                                         -- 表空間文件描述符緩存,提高數據表打開效率
+table_definition_cache                        -- 表定義文件描述符緩存,提高數據表打開效率
會話緩存包括:
 total_thread_buffers= max_connections  * (
  read_buffer_size             -- 順序讀緩沖,提高順序讀效率
+read_rnd_buffer_size   -- 隨機讀緩沖,提高隨機讀效率
+sort_buffer_size           -- 排序緩沖,提高排序效率
+join_buffer_size           -- 表連接緩沖,提高表連接效率
+binlog_cache_size       -- 二進制日志緩沖,提高二進制日志寫入效率
+tmp_table_size            -- 內存臨時表,提高臨時表存儲效率
+thread_stack                -- 線程堆棧,暫時寄存SQL語句/存儲過程
+thread_cache_size       -- 線程緩存,降低多次反復打開線程開銷,模擬連接池
)
 
內存相關配置參數介紹:

全局內存部分:

innodb_buffer_pool
• InnoDB高速緩沖(簡稱IBP),對Innodb很重要。
• 應該把它設置得大一些,單實例,建議設置為可用RAM的50~80%。
• InnoDB不依賴OS,而自己緩存了所有數據,包括索引數據,行數據,等等。這點跟MyISAM有差別。
• 查詢或更新需要對IBP加鎖,影響並發
• IBP有一塊buffer用於插入緩沖。在插入的時候,先寫入內存,之后再合並后順序寫入磁盤。在命並到磁盤上的時候,會引發較大的IO操作,對實時操作造成影響(看上去是抖動,tps變低)
• show global status like ‘innodb_buffer_pool_%’ 查看IBP狀態,單位是page(16kb)
• Innodb_buffer_pool_wait_free 如果較大,需要加大IBP設置
• InnoDB會定時(約每10秒)將臟頁刷新到磁盤,默認每次刷新10頁;
• 要是臟頁超過了指定數量(innodb_max_dirty_pages_pct),InnoDB則會每秒刷100頁臟頁 
 innodb_buffer_pool_instances可以設置pool的數量
 show engine innodb status\G     可以查看innodb引擎狀態
mysql> show global status like 'innodb_buffer_%';
+---------------------------------------+---------+
| Variable_name                         | Value   |
+---------------------------------------+---------+
| Innodb_buffer_pool_pages_data         | 154     |
| Innodb_buffer_pool_bytes_data         | 2523136 |
| Innodb_buffer_pool_pages_dirty        | 0       |                         臟數據
| Innodb_buffer_pool_bytes_dirty        | 0       |
| Innodb_buffer_pool_pages_flushed      | 1       |
| Innodb_buffer_pool_pages_free         | 8038    |                    空閑,要乘以16k
| Innodb_buffer_pool_pages_misc         | 0       |
| Innodb_buffer_pool_pages_total        | 8192    |
| Innodb_buffer_pool_read_ahead_rnd     | 0       |
| Innodb_buffer_pool_read_ahead         | 0       |      預讀的頁數
| Innodb_buffer_pool_read_ahead_evicted | 0       |      預讀的頁數,但是沒有被讀取就從緩沖池中被替換的頁的數量,一般用來判斷預讀的效率。
| Innodb_buffer_pool_read_requests      | 563     |      從緩沖池中讀取的次數。
| Innodb_buffer_pool_reads              | 155     |      表示從物理磁盤讀取的頁數
| Innodb_buffer_pool_wait_free          | 0       |
| Innodb_buffer_pool_write_requests     | 1       |
+---------------------------------------+---------+
15 rows in set (0.00 sec)
Innodb_data_read:總共讀入的字節數。
Innodb_data_reads:發起讀請求的次數,每次讀取可能需要讀取多個頁。
 buffer pool利用率:
ib_bp_hit=(1 - Innodb_buffer_pool_reads/Innodb_buffer_pool_read_requests)*100%
  buffer poo 命中率 
= (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
 
  innodb_additional_mem_pool_size
數據字典以及內部數據結構緩存,表數量越多,相應的內存需要越大。
默認8M,通常設置為8~32M足夠,一般建議設置為16M,如果確實不夠用,那么會從系統中請求增加分配內存,並且錯誤日志中會提醒,目前至少還未發生過。
 
  innodb_log_buffer_size
show global status 查看 Innodb_log_waits 是否大於0,是的話,就需要提高 innodb_log_buffer_size,否則維持原樣。
show global stauts 查看30~60秒鍾 Innodb_os_log_written 的間隔差異值,即可計算出 innodb_log_buffer_size 設置多大合適。
默認8M,一般設置為16 ~ 64M足夠了。
  1. Innodb_log_waits,可用log buffer不足,等待釋放次數,數量較大時需要加大log buffer
  2. Innodb_log_write_requests, log寫請求次數
  3. Innodb_log_writes, log物理寫次數
  4. Innodb_os_log_fsyncs, log寫入時,調用rsync()次數 
  5. Innodb_os_log_pending_fsyncslog文件等待fsync()操作次數 
  6. Innodb_os_log_pending_writes, log寫等待次數
  7. Innodb_os_log_written, log寫入總字節數
  8. innodb log buffer作用:InnoDB log隨機IO
整合率Innodb_log_write_requests/ Innodb_log_writes
 
key_buffer_size  :myisam引擎中表的索引   的緩存大小,默認值  =   16M,單個 key_buffer_size最大只有4G(32-bit系統下最大4G,64-bit下可以超過)
 若主要使用myisam,設置最高不超過物理內存的20%~50%, 即便全是innodb表,沒用MyISAM,也有必要設置該值用於緩存臨時表之索引,推薦32MB, (如果內存tmp_table_size Created_tmp_tables 不夠的話,內部的臨時磁盤表是MyISAM表 Created_tmp_disk_tables (新版本可能是innodb表)
可以使用檢查狀態(show global status)值'created_tmp_disk_tables'得知詳情。
| Created_tmp_disk_tables                  |  0           |
| Created_tmp_files                        |  5           |
| Created_tmp_tables                       |  4           |
 Key_read_requests           myisam引擎上總讀取請求次數
Key_reads                               myisam從物理硬盤上讀索引的次數
Key_write_requests           myisam引擎上總寫入請求次數
Key_writes                               myisam從物理硬盤上寫索引的次數
 key buffer命中率
讀命中率key_buffer_read_hits = (1 - key_reads/key_read_requests) * 100%
寫命中率key_buffer_write_hits = (1 - key_writes/key_write_requests) * 100%
 
  query_cache_size
• 建議直接關閉不使用
• MySQL高速查詢緩存池(簡稱QC)。
• 將SELECT語句和查詢結果存放在緩沖區中,若有同樣的SELECT語句(區分大小寫),將直接從緩沖區中讀取結果。
• show global status like ‘Qcache_%‘ 查看QC,可以知道QC設置是否合理
       如果 Qcache_lowmem_prunes 的值非常大,則表明經常出現緩沖不夠的情況
       如果 Qcache_hits 的值非常大,則表明查詢緩沖使用非常頻繁,此時需要增加緩沖大小
       如果 Qcache_hits 的值不大,則表明你的查詢重復率很低,這種情況下使用查詢緩沖反而會影響效率,那么可以考慮不用查詢緩沖
• 在SELECT語句中加入SQL_NO_CACHE可以明確表示不使用查詢緩沖
• query_cache_limit = 2M,不緩存超過2M的查詢結果
query_cache_min_res_unit = 512K,設置每個QC單元大小,提高QC利用率(Qcache_queries_in_cache不大,但Qcache_free_memory較大,就需要減小query_cache_min_res_unit )
 query cache命中率:
Query_cache_hits = 1 – (qcache_hits / (qcache_hits + com_select)) * 100%
 
thread_cache_size
Thread_Cache 中存放的最大連接線程數。
在短連接的應用中Thread_Cache的功效非常明顯,因為在應用中數據庫的連接和創建是非常頻繁的,如果不使用 Thread_Cache那么消耗的資源是非常可觀的!在長連接中雖然帶來的改善沒有短連接的那么明顯,但是好處是顯而易見的。
但並不是越大越好,有可能大了反而浪費資源。
thread cache命中率:
Thread_Cache_Hit=(Connections-Thread_created)/Connections*100%
 
TABLE_OPEN_CACHE(5.1.3及以前版本名為TABLE_CACHE)
由於MySQL是多線程的機制,為了提高性能,每個線程都是獨自打開自己需要的表的文件描述符,而不是通過共享已經打開的.針對不同存儲引擎處理的方法當然也不一樣。
在MyISAM表引擎中,數據文件的描述符(descriptor)是不共享的,但是索引文件的描述符卻是所有線程共享的。
Innodb中和使用表空間類型有關,假如是共享表空間那么實際就一個數據文件,當然占用的數據文件描述符就會比獨立表空間少。
  幾個關於table_cache的狀態值:
Open_tables:當前打開的表的數量
Opened_tables:歷史上全部已經打開的表總數,如果 Opened_tables 較大,table_open_cache 值可能需要加大。
 
如果Open_tables的值已經接近table_cache的值,且Opened_tables還在不斷變大,則說明mysql正在將緩存的表釋放以容納新的表,此時可能需要加大table_cache的值。對於大多數情況。通常比較適合的建議值:
 Open_tables / table_open_cache <= 0.95
 
  table_definition_cache
從MySQL 5.1開始,數據表文件描述符被分開為數據文件及數據表定義文件兩部分。表定義文件緩存可以放在專屬的 table_definition_cache 中。
表定義文件緩存相比表文件描述符緩存所消耗的內存更小,其默認值是 400。
 狀態值:
Open_table_definitions:表定義文件 .frm 被緩存的數量
Opened_table_definitions:歷史上總共被緩存過的 .frm 文件數量。
 
其它幾個小內存,內存計算公式:
• adaptive index hash, size= innodb_buffer_pool / 64, 自適應哈希索引,用來管理buffer pool的哈希索引。 隨着buffer的頻繁更新,會隨之上升
• system dictionary hash, size = innodb_buffer_pool_size / 256,基本固定,數據字典信息
• memory for sync_array, which is used for syncronization primitives, size = OS_THREADS * 152
• memory for os_events, which are also used for syncronization primitives, OS_THREADS * 216
• memory for locking system, size=5 * 4 * NBLOCKS(NBLOCKS,innodb buffer pool的block數量),隨着並發/行鎖增加,會隨之上升
其中 
OS_THREADS = 
如果 innodb_buffer_pool_size >= 1000Mb,則為:50000
否則如果 innodb_buffer_pool_size >= 8Mb,則為:10000
否則為: 1000 (*nixes平台下通用)
• NBLOCKS = innodb_buffer_pool_size/8192
 


會話級內存部分:

tmp_table_size(相當於pga)
是MySQL的臨時表緩沖大小。所有聯合在一個DML指令內完成,並且大多數聯合甚至可以不用臨時表即可以完成。大多數臨時表是基於內存的(HEAP)表。具有大的記錄長度的臨時表 (所有列的長度的和)或包含BLOB列的表存儲在硬盤上。如果某個內部heap(堆積)表大小超過tmp_table_size,MySQL可以根據需要自動將內存中的heap表改為基於硬盤的MyISAM表。還可以通過設置tmp_table_size選項來增加臨時表的大小。也就是說,如果調高該值,MySQL同時將增加heap表的大小,可達到提高聯接查詢速度的效果。(Using temporary)
不負責限制 MEMORY/HEAP表最大容量,如果執行SQL產生臨時表超過 tmp_table_size/max_heap_table_size,則會產生基於磁盤的MyISAM表。
一般64~128m就可以.
排序時sort_buffer_size放不下時,要用到內存tmp_table_size,還是磁盤臨時表?
 tmp table命中率
每次使用臨時表都會增大  Created_tmp_tables;基於磁盤的表也會增大  Created_tmp_disk_tables
對於這個比率,並沒有什么嚴格的規則,因為這依賴於所涉及的查詢。長時間觀察 Created_tmp_disk_tables 會顯示所創建的磁盤表的比率,您可以確定設置的效率。 
tmp_table_size 和 max_heap_table_size 都可以控制臨時表的最大大小,因此請確保在 my.cnf 中對這兩個值都進行了設置。
 
  max_heap_table_size
這個變量定義了用戶可以創建的內存表(memory table)的大小.這個值用來計算內存表的最大行數值。
這個變量支持動態改變,即set @max_heap_table_size=#,但是對於已經存在的內存表就沒有什么用了,除非這個表被重新創建(create table)或者修改(alter table)或者truncate table。
服務重啟也會設置已經存在的內存表為全局max_heap_table_size的值。
這個變量和tmp_table_size一起限制了內部內存表的大小。
它和tmp_table_size的區別是,負責設置MEMORY/HEAP表最大容量,不管其他執行SQL產生的臨時表,如果內存不夠用,則不允許寫入新的數據,MEMORY/HEAP表也不會轉成磁盤表,只會告警超限后拒絕寫入。
一般它和tmp_table_size設置一樣就可以了。
 
  binlog_cache_size
(dml在執行commit前,將日志寫入緩存。如果語句大於該值,線程則打開臨時文件來保存事務。線程結束后臨時文件被刪除。commit時,mysqld將事務寫入binlog文件。)
在事務過程中容納二進制日志SQL 語句的緩存大小。二進制日志緩存是服務器支持事務存儲引擎並且服務器啟用了二進制日志(—log-bin 選項)的前提下為每個客戶端分配的內存。
如果系統中經常會出現多語句事務的話,可以嘗試增加該值的大小,以獲得更好的性能。當然, 我們可以通過MySQL 的以下兩個狀態變量來判斷當前的binlog_cache_size 的狀況:Binlog_cache_use 和Binlog_cache_disk_use。“max_binlog_cache_size”:和"binlog_cache_size"相對應,但是所代表的是binlog 能夠使用的最大cache 內存大小。當我們執行多語句事務的時候,max_binlog_cache_size 如果不夠大的話,系統可能會報出“ Multi-statement transaction required more than 'max_binlog_cache_size' bytes ofstorage”的錯誤。
binlog cache命中率
binlog hit ratio  = (Binlog_cache_use) /( Binlog_cache_use  + Binlog_cache_disk_use) ,一般要大於 98%
Binlog_cache_use狀態變量顯示了使用該緩沖區(也可能是臨時文件)保存語句的事務的數量。
Binlog_cache_disk_use狀態變量顯示了這些事務中實際上有多少必須使用臨時文件。
DML 在 commit后,發現這2個值會有變化
 
bulk_insert_buffer_size(每線程分配,MyISAM特有,表的插入緩存)
專用於MyISAM引擎,用一個特別的類似樹形結構體緩存,用以提高 INSERT ... SELECT, INSERT ... VALUES (...), (...) 以及 LOAD DATA寫數據到非空表的情景。
每個線程分配,默認8M,可以設置為 0 來關閉這個buffer。
 
 
myisam_sort_buffer_size(用到才分配,MyISAM特有)
MyISAM表在做修復時,用於提高索引文件修復效率的buffer,或者用以創建索引時提高效率。
默認值8M,一般128M ~ 256M 足夠了。
 
下面幾個buffer size,一般設置為128K ~ 2M足夠。如果單進程需求量大,set read_buffer_size = 128 * 1024 * 1024;
read_buffer_size  順序讀buffer
是MySQL讀入緩沖區大小。對表進行順序掃描的請求將分配一個讀入緩沖區,MySQL會為它分配一段內存緩沖區。read_buffer_size變量控制這一緩沖區的大小。如果對表的順序掃描請求非常頻繁,並且你認為頻繁掃描進行得太慢,可以通過增加該變量值以及內存緩沖區大小提高其性能。
Handler_read_next / Com_select 得出了表掃描比率
 
read_rnd_buffer_size   隨機讀buffer
是MySQL的隨機讀緩沖區大小。當按任意順序讀取行時(例如,按照排序順序),將分配一個隨機讀緩存區。進行排序查詢時,MySQL會首先掃描一遍該緩沖,以避免磁盤搜索,提高查詢速度,如果需要排序大量數據,可適當調高該值。但MySQL會為每個客戶連接分配該緩沖區,所以應盡量適當設置該值,以避免內存開銷過大。
[上面有可能不准,看下面這段]
當執行完根據索引排序操作后,按照一定排序順序讀取數據時,這些數據會放在 read_rnd_buffer 中以避免的磁盤搜索。不是指隨機讀取的緩沖。
 
 
sort_buffer_size
是MySQL執行排序使用的緩沖大小。如果想要增加ORDER BY的速度,首先看是否可以讓MySQL使用索引而不是額外的排序階段。如果不能,可以嘗試增加sort_buffer_size變量的大小(執行計划中,如果顯示using filesort,就說明會用到sort buffer)。
Sort_merge_passes 包括兩步。MySQL 首先會嘗試在內存中做排序,使用的內存大小由系統變量 Sort_buffer_size 決定, 如果它的大小不夠把所有的記錄都讀到內存中,MySQL 就會把每次在內存中排序的結果存到臨時文件中,等 MySQL 找到所有記錄之后,再把臨時文件中的記錄做一次排序。這個臨時文件也會增加Created_tmp_disk_tables嗎?
再次排序就會增加 Sort_merge_passes.實際上,MySQL 會用另一個臨時文件來存再次排序的結果,所以通常會看到 Sort_merge_passes 增加的數值是建臨時文件數的兩倍。
因為用到了臨時文件,所以速度可能會比較慢,增加 Sort_buffer_size 會減少 Sort_merge_passes 和 創建臨時文件的次數。但不能盲目增加 Sort_buffer_size ,因為並不一定能提高速度。

join_buffer_size
應用程序經常會出現一些兩表(或多表)JOIN的操作需求,MySQL在完成某些 Join 需求的時候(all row join/ all index join/ range index scan join),為了減少參與JOIN的“被驅動表”的讀取次數以提高性能,需要使用到 JOIN Buffer 來協助完成 JOIN操作。當 JOIN Buffer 太小,MySQL 不會將該 Buffer 存入磁盤文件,而是先將Join Buffer中的結果集與需要 Join 的表進行 Join 操作,然后清空 Join Buffer 中的數據,繼續將剩余的結果集寫入此 Buffer 中,如此往復。這勢必會造成被驅動表需要被多次讀取,成倍增加 IO 訪問,降低效率。(執行計划中,如果顯示Using join buffer,就說明會用到JOIN Buffer).
 
 多種JOIN情況:plain index scans(普通索引掃描), range index scans(范圍索引掃描), do not use indexes and thus perform full table scans(沒有索引的全表掃描)
最好是添加適當的索引,而不是純粹的加大 join_buffer_size。
任何兩個表間的全表 join 就會分配一次 join buffer,也就是說,如果有3個表join,就會分配2次join buffer。
 
Select_full_join,表關聯時,由於沒有索引產生的掃描次數,大於0時,需要注意檢查是否有合適的索引
Select_full_range_join,表關聯時,驅動表使用范圍掃描次數
 
 thread_stack 
主要用來存放每一個線程自身的標識信息,如線程id,線程運行時基本信息等等,我們可以通過 thread_stack 參數來設置為每一個線程棧分配多大的內存。一般默認的256KB就足夠了。
 
net_buffer_length(每線程分配)
每個客戶端連接時,用以維持連接緩沖以及讀取結果緩沖。初試分配預設值,在有需要時,則會自動擴大到 max_allowed_packet 大小,然后再回收到預設的 net_buffer_length 大小。
最小1K,最大1M,默認值是16K。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM