InnoDB是MySQL使用最多的存儲引擎,通常InnoDB狀態可以通過show engine innodb status\G查看。
由於MySQL不同版本採用InnoDB引擎版本不同,5.6後對show engine innodb status信息進行了優化,本文環境爲5.7。
MySQL版本 | InnoDB引擎版本 |
5.1.x | 1.0.x版本(官方稱爲InnoDB Plugin) |
5.5.x | 5.5(1.1.x版本),InnoDB被Oracle收購後 |
5.6.x | 5.6(1.2.x版本) |
5.7.x | 5.7 |
8.0.x | 8.0 |
show engine innodb status統計信息
需要注意一點:show engine innodb status顯示的不是當前狀態,而是過去某個時間範圍內InnoDB存儲引擎的狀態。
向右拉
Per second averages calculated from the last 59 seconds
在顯示前端可看到以上信息,代表查詢的信息爲過去59秒內每2秒的平均值。
show engine innodb status主要包括以下幾個部分:
BACKGROUND THREAD |
後臺Master線程 |
SEMAPHORES | 信號量信息 |
LATEST DETECTED DEADLOCK | 最近一次死鎖信息,只有產生過死鎖纔會有 |
TRANSACTIONS | 事物信息 |
FILE I/O | IO Thread信息 |
INSERT BUFFER AND ADAPTIVE HASH INDEX | INSERT BUFFER和自適應HASH索引 |
LOG | 日誌 |
BUFFER POOL AND MEMORY | BUFFER POOL和內存 |
INDIVIDUAL BUFFER POOL INFO |
如果設置了多個BUFFER POOL實例,這裏顯示每個BUFFER POOL信息。可通過innodb_buffer_pool_instances參數設置 |
ROW OPERATIONS | 行操作統計信息 |
END OF INNODB MONITOR OUTPU | 輸出結束語 |
BACKGROUND THREAD
InnoDB存儲引擎的核心操作大部分都集中在Mater Thread後臺線程中。
MySQL5.5版本之前:
-----------------
BACKGROUND THREAD
-----------------
srv_master_thread loops: 846676 1_second, 846675 sleeps, 84665 10_second, 17 background, 17 flush
srv_master_thread log flush and writes: 854189
MySQL 5.6之後對Master Thread進行了優化,去除了sleeps的信息,srv_active爲之前的每秒的循環,srv_idle爲每10秒的的循環,srv_shutdown爲停止的循環,通常爲0,只在MySQL關閉時纔會增加。
BACKGROUND THREAD
-----------------
srv_master_thread loops: 3911776 srv_active, 0 srv_shutdown, 309625 srv_idle
srv_master_thread log flush and writes: 4221384
上面可以看出主循環每10秒進行了309625次,每秒進行了3911776次,每10秒的操作符合1:10。
負載低的情況下日誌緩衝刷盤次數,4221384 ≈ 3911776+309625。
根據循環次數可大概判斷當前數據庫負載情況。如果每秒循環次數少,每10秒次數多,證明當前負載很低;如果每秒循環次數多,每10秒次數少,遠大於10:1,證明當前負載很高。
SEMAPHORES
當前等待線程的列表及事件計數器,可以評估當前負載情況。
----------
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 58961200
OS WAIT ARRAY INFO: signal count 125268732
Mutex spin waits 770371493, rounds 6482840874, OS waits 20699077
RW-shared spins 0, rounds 115276716, OS waits 14655922
RW-excl spins 0, rounds 987115172, OS waits 12384598
RW-sx spins 40484350, rounds 419545112, OS waits 4476477
Spin rounds per wait: 115276716.00 RW-shared, 987115172.00 RW-excl, 10.36 RW-sx
OS WAIT ARRAY INFO | reservation count:表示InnoDB產生了多少次OS WAIT; signal count:表示進入OS WAIT的線程被喚醒次數 |
Mutex(5.7後去除) | spins:空轉次數,通過innodb_sync_spin_loops控制,超過則轉到OS waits; spin waits:spin線程無法獲取鎖而進入Spin wait; rounds:spin wait進行輪詢檢查mutexes的次數; OS waits:線程放棄spin wait進入掛起狀態。 |
RW-shared | RW-shared 共享鎖 |
RW-excl | RW-excl 排他鎖 |
RW-sx | 5.7後新增; RW-sx 共享排他鎖 |
Spin rounds per wait | rounds / spins = 值 |
要明白InnoDB如何處理互斥量(Mutexes),以及什麼是兩步獲得鎖(two-step approach)。
- 首先進程試圖獲得一個鎖,如果此鎖被它人佔用。它就會執行所謂的spin wait,即所謂循環的查詢“鎖被釋放了嗎?”。
- 如果在循環過程中,一直未得到鎖釋放的信息,則其轉入OS WAIT,即所謂線程進入掛起(suspended)狀態。
- 直到鎖被釋放後,通過信號(singal)喚醒線程。
Spin wait的消耗遠小於OSwaits。Spin wait利用cpu的空閒時間,檢查鎖的狀態,OS Wait會有所謂content switch,從CPU內核中換出當前執行線程以供其它線程使用。所以應儘量減少OS waits,可以通過innodb_sync_spin_loops參數來平衡spin wait和os wait。Mutex信息可通過show engine innodb mutex查看。
LATEST DETECTED DEADLOCK
記錄最近一次死鎖信息,只有產生過死鎖纔會有記錄。
------------------------
LATEST DETECTED DEADLOCK
------------------------
190425 18:00:13
*** (1) TRANSACTION:
TRANSACTION 231E7C5DF, ACTIVE 0 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 4 lock struct(s), heap size 1248, 3 row lock(s)
MySQL thread id 1346996, OS thread handle 0x7fd968454700, query id 760545285 10.10.x.x app_user updating
DELETE
FROM db_0.table_0
WHERE ORDER_ID IN ( 456787464 , 456787465 )
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 5 page no 6064 n bits 824 index `orderId_index` of table `db_0`.`table_0` trx id 231E7C5DF lock_mode X waiting
Record lock, heap no 180 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
0: len 8; hex 80000015eb6a1041; asc j A;;
1: len 8; hex 800000002018fce2; asc ;
*** (2) TRANSACTION:
TRANSACTION 231E7C5DD, ACTIVE 0 sec starting index read, thread declared inside InnoDB 1
mysql tables in use 1, locked 1
5 lock struct(s), heap size 1248, 4 row lock(s)
MySQL thread id 1348165, OS thread handle 0x7fd96669f700, query id 760545283 10.10.x.x app_user updating
DELETE
FROM db_0.table_0
WHERE ORDER_ID IN ( 456787464 , 456787465 )
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 5 page no 6064 n bits 824 index `orderId_index` of table `db_0`.`table_0` trx id 231E7C5DD lock_mode X locks rec but not gap
Record lock, heap no 180 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
0: len 8; hex 80000015eb6a1041; asc j A;;
1: len 8; hex 800000002018fce2; asc ;;
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 5 page no 6064 n bits 824 index `orderId_index` of table `db_0`.`table_0` trx id 231E7C5DD lock_mode X waiting
Record lock, heap no 180 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
0: len 8; hex 80000015eb6a1041; asc j A;;
1: len 8; hex 800000002018fce2; asc ;;
*** WE ROLL BACK TRANSACTION (1)
死鎖是指兩個或兩個以上的進程在執行過程中,因爭奪資源而造成的一種互相等待的現象。正常死鎖會自動釋放,innodb有一個內在的死鎖檢測工具,當死鎖超過一定時間後,會回滾其中一個事務,innodb_lock_wait_timeout可配置死鎖等待超時時間。
死鎖在兩情況下最容易產生:
-
高併發同時操作同一條數據
-
存在主鍵和輔助索引,加鎖順序相反
避免死鎖方法即降低併發,操作數據時使加鎖順序相同。
TRANSACTIONS
包含了InnoDB事務(transaction)的統計信息。
------------
TRANSACTIONS
------------
Trx id counter 2409176
Purge done for trx's n:o < 2409171 undo n:o < 0 state: running but idle
History list length 31
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 421224214038352, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421224214044736, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421224214039264, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 2409171, ACTIVE 1549 sec fetching rows, thread declared inside InnoDB 3871
mysql tables in use 1, locked 0
0 lock struct(s), heap size 1136, 0 row lock(s)
MySQL thread id 653597, OS thread handle 140289889908480, query id 2528936 127.0.0.1 root Sending data
SELECT /*!40001 SQL_NO_CACHE */ * FROM `table`
Trx id counter | 當前事物ID |
Purge done for trx's | 正在清理掉的transaction ID |
History list length | 記錄了undo spaces內未清掉的事務個數,Purge的原則是記錄沒有被其它事務繼續使用。 |
LIST OF TRANSACTIONS FOR EACH SESSION | 每個session的事物狀態 |
當前活躍的事物狀態爲ACTIVE,事物的詳細信息,包括線程ID、執行時間、用戶、SQL等。正在使用1個表,涉及鎖的表0個。
FILE I/O
在InnoDB中大量使用了AIO(Async IO)來處理IO 請求,IO Thread主要是負責這些IO請求的回調處理,通過調用fsync()函數協調內存與磁盤之間的數據。
--------
FILE I/O
--------
I/O thread 0 state: waiting for completed aio requests (insert buffer thread)
I/O thread 1 state: waiting for completed aio requests (log thread)
I/O thread 2 state: waiting for completed aio requests (read thread)
I/O thread 3 state: waiting for completed aio requests (read thread)
I/O thread 4 state: waiting for completed aio requests (read thread)
I/O thread 5 state: waiting for completed aio requests (read thread)
I/O thread 6 state: waiting for completed aio requests (read thread)
I/O thread 7 state: waiting for completed aio requests (read thread)
I/O thread 8 state: waiting for completed aio requests (read thread)
I/O thread 9 state: waiting for completed aio requests (read thread)
I/O thread 10 state: waiting for completed aio requests (write thread)
I/O thread 11 state: waiting for completed aio requests (write thread)
I/O thread 12 state: waiting for completed aio requests (write thread)
I/O thread 13 state: waiting for completed aio requests (write thread)
I/O thread 14 state: waiting for completed aio requests (write thread)
I/O thread 15 state: waiting for completed aio requests (write thread)
I/O thread 16 state: waiting for completed aio requests (write thread)
I/O thread 17 state: waiting for completed aio requests (write thread)
Pending normal aio reads: [0, 0, 0, 0, 0, 0, 0, 0] , aio writes: [0, 0, 0, 0, 0, 0, 0, 0] ,
ibuf aio reads:, log i/o's:, sync i/o's:
Pending flushes (fsync) log: 0; buffer pool: 0
15234061 OS file reads, 304461183 OS file writes, 73899457 OS fsyncs
0.00 reads/s, 0 avg bytes/read, 0.24 writes/s, 0.17 fsyncs/s
InnoDB1.0版本之前有4個IO線程,1.1後做了優化,Purge Thread從Master Thread獨立出來,Purge Cleaner Thread從InnoDB1.2版本引入,都是爲了減輕Master Thread的工作,提高CPU利用率。
insert buffer thread | 合併插入緩衝,insert buffer維護非唯一輔助索引 |
log thread | 負責異步刷新事物日誌 |
read thread | 預讀,innodb_read_io_threads 默認4 |
write thread | 刷新髒頁緩衝,innodb_write_io_threads 默認4 |
purge thread | 回收已經使用並分配的undo頁,可設置多個 |
purge cleaner Thread | 刷新髒頁 |
顯示各個I/O thread的pending operations,pending的log和buffer pool thread的fsync()調用;
aio:代表的是異步IO(asynchronous I/O);
OS file:顯示了reads writes fsync() 調用次數。
INSERT BUFFER AND ADAPTIVE HASH INDEX
INSERT BUFFER即合併插入緩存,從innodb 1.0.x版本開始引入Change Buffer,是INSERT BUFFER升級版,即MySQL 5.1.x以上版本都支持,不僅包括INSERT BUFFER,還包括UPDATE BUFFER、DELETE BUFFER、PURGE BUFFER。
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1356, free list len 149402, seg size 149404, 2004231 merges
merged operations:
insert 1373793, delete mark 316276978, delete 5341003
discarded operations:
insert 0, delete mark 0, delete 0
Hash table size 298897, node heap has 1 buffer(s)
Hash table size 298897, node heap has 1 buffer(s)
Hash table size 298897, node heap has 0 buffer(s)
Hash table size 298897, node heap has 1 buffer(s)
Hash table size 298897, node heap has 1 buffer(s)
Hash table size 298897, node heap has 1 buffer(s)
Hash table size 298897, node heap has 2 buffer(s)
Hash table size 298897, node heap has 0 buffer(s)
Hash table size 298897, node heap has 1 buffer(s)
Hash table size 298897, node heap has 0 buffer(s)
Hash table size 298897, node heap has 0 buffer(s)
Hash table size 298897, node heap has 1 buffer(s)
Hash table size 298897, node heap has 1 buffer(s)
193.03 hash searches/s, 713.40 non-hash searches/s
Ibuf:size | 已經合併頁的數量 |
free list len | 空閒列表長度 |
seg size | Insert Buffer大小 |
merges | 合併次數 |
merged operations |
Change Buffer中每個操作次數; insert代表Insert Buffer; delete mark代表Delete Buffer; delete代表Purge Buffer; |
discarded operations | Change Buffer中無需合併的次數 |
hash searches/s | 通過hash索引查詢 |
non-hash searches/s | 不能通過hash索引查詢 |
可以看到自適應哈希索引大小、使用情況、每秒使用自適應哈希索引搜索情況。自適應HASH索引,由INNODB存儲引擎控制,只適合等值查詢,不適合範圍查詢。可通過innodb_adaptive_hash_index來禁用或啓動。
LOG
事物日誌的信息。
---
LOG
---
Log sequence number 33859450169594
Log flushed up to 33859450169564
Pages flushed up to 33859450169210
Last checkpoint at 33859450169201
0 pending log flushes, 0 pending chkp writes
15044267 log i/o's done, 0.10 log i/o's/second
InnoDB事物採用Write-Ahead log策略,即事物在提交時,先寫重做日誌,在修改頁。
Write-Ahead Log:如果一個頁在寫入磁盤時,必須先將內存中小於該頁LSN的日誌先寫入到磁盤中。
重做日誌有LSN、每個頁有LSN、Checkpoint也有LSN。
Log sequence number | 最新產生的日誌序列號 |
Log flushed up to | 已刷到磁盤的重做日誌的日誌號 |
Pages flushed up to | 已刷到磁盤的頁的日誌號 |
Last checkpoint at | 最後一次檢查點位置,數據和日誌一致的狀態 |
pending | 當前掛起的日誌讀寫操作 |
LSN記錄的是重做日誌的總量,單位是字節。以下三種情況會將重做日誌緩存刷到重做日誌文件:
-
Master Thread 每秒刷重做日誌緩存到重做日誌文件
-
innodb_flush_log_at_trx_commit=1時,每次事務提交刷重做日誌緩存到重做日誌文件
-
重做日誌緩衝池剩餘空間小於1/2時,刷重做日誌緩存到重做日誌文件
BUFFER POOL AND MEMORY
innodb_buffer_pool包含數據頁、索引頁、undo頁、insert buffer、數據字典、自適應哈希索引、鎖信息等。數據庫緩衝池是通過LRU列表管理的。
----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 19789774848
Dictionary memory allocated 3944999
Buffer pool size 1179504
Free buffers 8192
Database pages 1116347
Old database pages 411925
Modified db pages 3
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 74514305, not young 649973267
0.21 youngs/s, 0.17 non-youngs/s
Pages read 15233915, created 7356668, written 264739684
0.00 reads/s, 0.00 creates/s, 0.10 writes/s
Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not 0 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 1116347, unzip_LRU len: 0
I/O sum[48]:cur[0], unzip sum[0]:cur[0]
Total large memory allocated | 爲innodb 分配的總內存數(byte) |
Dictionary memory allocated | 爲innodb數據字典分配的內存數(byte) |
Buffer pool size | innodb_buffer_pool的頁數量 |
Free buffers | lru列表中的空閒頁數量 |
Database pages | lru列表中的非空閒頁數量 |
Old database pages | old子列表的頁數量 |
Modified db pages | 髒頁的數量 |
Pending reads | 掛起讀的數量 |
可以看到當前Buffer Pool Size共有1179504頁,即1179504*16K。新讀取到的頁默認插入LRU列表的5/8的位置。此值由innodb_old_blocks_pct控制,即前5/8稱爲new list,後面3/8的稱爲old list。Pages made young 顯示LRU列表中old list移到new list的次數,not young顯示仍在old list的次數。這兩個值受innodb_old_blocks_time影響,此值爲微秒。如果old list中超過30微秒不再讀取,則記錄not young,反之記錄爲Pages made young。
(root@localhost) [(none)] >show global variables like '%blocks%';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| innodb_old_blocks_pct | 37 |
| innodb_old_blocks_time | 30 |
+------------------------+-------+
youngs/s,non-youngs/s,表示每秒這兩類操作的次數。
Pages read,created,written,表示innodb被讀取,創建,寫入了多少頁及每秒的次數。
Buffer pool hit rate,表示緩衝池命中率,如果低於95%需要具體排查。
Pages read ahead,表示頁面預讀,隨機預讀的每秒頁數。
LRU中包含unzip_LRU,unzip_LRU是管理非16KB的壓縮表。
INDIVIDUAL BUFFER POOL INFO
可通過innodb_buffer_pool_instances 來配置多個緩衝池實例,默認爲1。可減少數據庫內部資源競爭,增加併發處理能力。如果分配多個緩衝池實例,每個緩衝池大小爲 innodb_buffer_pool_size / innodb_buffer_pool_instances 。
----------------------
INDIVIDUAL BUFFER POOL INFO
----------------------
---BUFFER POOL 0
Buffer pool size 147438
Free buffers 1024
Database pages 139530
Old database pages 51486
Modified db pages 0
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 8790743, not young 77467460
0.00 youngs/s, 0.00 non-youngs/s
Pages read 1856892, created 916430, written 30727167
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: 139530, unzip_LRU len: 0
I/O sum[6]:cur[0], unzip sum[0]:cur[0]
---BUFFER POOL 1
---BUFFER POOL 2
---BUFFER POOL 3
可以通過information_schema.INNODB_BUFFER_POOL_STATS視圖查看每個buffer_pool實例的信息,MySQL默認一個page大小爲16K,可以得出POOL_SIZE * innodb_buffer_pool_instances * 16K = innodb_buffer_pool_size。
(root@localhost) [information_schema] >select POOL_ID,POOL_SIZE,FREE_BUFFERS,DATABASE_PAGES,OLD_DATABASE_PAGES,MODIFIED_DATABASE_PAGES,PAGES_MADE_YOUNG,PAGES_NOT_MADE_YOUNG from information_schema.INNODB_BUFFER_POOL_STATS;
+---------+-----------+--------------+----------------+--------------------+-------------------------+------------------+----------------------+
| POOL_ID | POOL_SIZE | FREE_BUFFERS | DATABASE_PAGES | OLD_DATABASE_PAGES | MODIFIED_DATABASE_PAGES | PAGES_MADE_YOUNG | PAGES_NOT_MADE_YOUNG |
+---------+-----------+--------------+----------------+--------------------+-------------------------+------------------+----------------------+
| 0 | 90112 | 0 | 90109 | 33279 | 0 | 18064 | 132278807 |
| 1 | 90112 | 0 | 90109 | 33282 | 0 | 18342 | 132086061 |
| 2 | 90112 | 0 | 90110 | 33282 | 0 | 17631 | 132149779 |
+---------+-----------+--------------+----------------+--------------------+-------------------------+------------------+----------------------+
詳細說明同上。
ROW OPERATIONS
顯示了row 操作及其他一些統計信息。
--------------
ROW OPERATIONS
--------------
0 queries inside InnoDB, 0 queries in queue
0 read views open inside InnoDB
Process ID=444943, Main thread ID=139899621590784, state: sleeping
Number of rows inserted 172887566, updated 227534242, deleted 56676133, read 709667077
8.77 inserts/s, 8.04 updates/s, 0.00 deletes/s, 10.92 reads/s
queries,表示innodb內核中有多少個線程,隊列中有多少個線程。
read views open inside InnoDB,表示有多少個read view 被打開,一個read view 包含事物開始點數據庫內容的MVCC快照。
Process ID=444943,表示內核的主線程狀態。
Number of rows inserted、updated、deleted、read,表示多少行被插入,更新和刪除,讀取及每秒信息,可用於監控。
可通過以下命令查看:
(root@localhost) [(none)] >show global status like 'Innodb_rows_%';
+----------------------+-----------+
| Variable_name | Value |
+----------------------+-----------+
| Innodb_rows_deleted | 56676133 |
| Innodb_rows_inserted | 172887566 |
| Innodb_rows_read | 709667077 |
| Innodb_rows_updated | 227534242 |
+----------------------+-----------+
(root@localhost) [(none)] >show global status like 'Uptime';
+---------------+---------+
| Variable_name | Value |
+---------------+---------+
| Uptime | 1757270 |
+---------------+---------+
END OF INNODB MONITOR OUTPUT
InnoDB信息結束語。
----------------------------
END OF INNODB MONITOR OUTPUT
============================
如果看不到這行輸出,可能是有大量事務或者有一個大的死鎖截斷了輸出信息。