innodb_buffer_pool已佔用內存的明細信息,能夠按照庫\表的維度來統計html
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ; SELECT database_name, SUM(compressed_size)/1024/1024 AS allocated_memory, SUM(data_size)/1024/1024 AS data_memory, SUM(is_hashed)*16/1024 AS is_hashed_memory, SUM(is_old)*16/1024 AS is_old_memory FROM ( SELECT case when INSTR(TABLE_NAME,'.')>0 then replace(SUBSTRING(TABLE_NAME,1,INSTR(TABLE_NAME,'.')-1),'`','') else 'system_database' end as database_name, case when INSTR(TABLE_NAME,'.')>0 then replace(SUBSTRING(TABLE_NAME,INSTR(TABLE_NAME,'.')+1),'`','') ELSE 'system_obj' END AS table_name, if(compressed_size = 0, 16384, compressed_size) AS compressed_size, data_size, if(is_hashed = 'YES',1,0) is_hashed, if(is_old = 'YES',1,0) is_old FROM information_schema.innodb_buffer_page WHERE TABLE_NAME IS NOT NULL ) t GROUP BY database_name ORDER BY allocated_memory DESC LIMIT 10;
緩存命中率統計及冷熱數據變化python
查詢緩存命中率相關:
information_schema.innodb_buffer_pool_stats中的數據行數是跟buffer_pool_instance一致的
也就是每一個一行數據來描述一個buffer_pool_instance,這裏簡單取和,緩存命中率取平局值的方式來統計
須要注意的是
1,modified_database_pages是實時的,就是內存中的髒頁的數量,經checkpoint以後被刷新到磁盤,所以會時大時小。
2,pages_made_young和pages_not_made_young是累積的增長的,不會減小,就是MySQL實例截止到目前位置,作了多少pages_not_made_young和pages_not_made_young。
3,hit_rate在負載較低的狀況下,沒有參考意義,這一點很奇怪,低負載狀況下,會發現不少buffer_pool的hit_rate是0。
反覆測試的過程當中忽然意識到,hit_rate的計算,是否是以某個時間間隔爲基準,統計這個時間段內請求的命中率,若是這一小段時間內沒有請求,統計出來的hit_rate就是0。
4,與其餘視圖不通,information_schema.innodb_buffer_pool_stats中的數據會在服務重啓後清零。mysql
SELECT SUM(modified_database_pages) AS total_modified_database_pages, SUM(pages_made_young) AS total_pages_made_young, SUM(pages_not_made_young) AS total_pages_not_made_young, SUM(hit_rate)/COUNT(hit_rate)*1000 AS hit_rate FROM ( SELECT pool_id, pool_size, database_pages, old_database_pages, modified_database_pages, pages_made_young, pages_not_made_young, hit_rate FROM information_schema.innodb_buffer_pool_stats )t;
參考http://www.javashuo.com/article/p-mvxuhrbs-br.html這裏對這pages_made_young和page_not_made_young,我的以爲解釋的很是好。sql
這裏低負載下的information_schema.innodb_buffer_pool_stats中的信息,hit_rate的值簡直難以想象。
這個實例是4GB的內存,基本上沒有訪問量,hit_rate居然出來好多值爲0的狀況。數據庫
相反在對當前實例作壓力測試的時候,這個數據看起來纔是正常的,包括modified_database_pages,pages_made_young,pages_not_made_young,hit_rate緩存
這裏用mysqlslap 作混合讀寫的壓力測試網絡
./mysqlslap -uroot -proot -h127.0.0.1 -P8000 --concurrency=100 --iterations=10000 --auto-generate-sql --auto-generate-sql-add-autoincrement --auto-generate-sql-load-type=mixed --engine=innodb --number-of-queries=10000
用python定時打印innodb_buffer_pool_stats併發
import pymysql import logging import time import decimal def execute_query(conn_dict,sql): conn = pymysql.connect(host=conn_dict['host'], port=conn_dict['port'], user=conn_dict['user'], passwd=conn_dict['password'], db=conn_dict['db']) cursor = conn.cursor(pymysql.cursors.DictCursor) cursor.execute(sql) list = cursor.fetchall() cursor.close() conn.close() return list def check_innodb_buffer_pool_stats(flag,conn_dict): result = execute_query(conn_dict, '''SELECT modified_database_pages, pages_made_young, pages_not_made_young, hit_rate FROM information_schema.innodb_buffer_pool_stats;''') if result: column = result[0].keys() current_row = '' if(flag<=0): for key in column: current_row += str(key) + " " print(current_row) for row in result: current_row = '' for key in row.values(): current_row += str(key) + " " print(current_row) if __name__ == '__main__': conn = {'host': '127.0.0.1', 'port': my_port, 'user': 'root', 'password': '***', 'db': 'mysql', 'charset': 'utf8mb4'} flag = 0 while 1>0: check_innodb_buffer_pool_stats(flag,conn) time.sleep(3) flag = 1
這樣子看下來,這個統計仍是比較正常的。負載均衡
hit_rate的計算,是否是以某個時間間隔爲基準,統計這個時間段內請求的命中率,若是這一小段時間內沒有請求,統計出來的hit_rate就是0?函數
基於表的讀寫的行的次數統計,這是一個累計值,單純的看這個值自己,我的以爲意義不大,須要定時收集計算差值,才具有參考意義。
如下按照庫級別統計表的讀寫狀況。
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ; SELECT database_name, IFNULL(cast(sum(total_read) as signed),0) AS total_read, IFNULL(cast(sum(total_written) as signed),0) AS total_written, IFNULL(cast(sum(total) AS SIGNED),0) AS total_read_written FROM ( SELECT substring(REPLACE(file, '@@datadir/', ''),1,instr(REPLACE(file, '@@datadir/', ''),'/')-1) AS database_name, count_read, case when instr(total_read,'KiB')>0 then replace(total_read,'KiB','')/1024 when instr(total_read,'MiB')>0 then replace(total_read,'MiB','')/1024 when instr(total_read,'GiB')>0 then replace(total_read,'GiB','')*1024 END AS total_read, case when instr(total_written,'KiB')>0 then replace(total_written,'KiB','')/1024 when instr(total_written,'MiB')>0 then replace(total_written,'MiB','') when instr(total_written,'GiB')>0 then replace(total_written,'GiB','')*1024 END AS total_written, case when instr(total,'KiB')>0 then replace(total,'KiB','')/1024 when instr(total,'MiB')>0 then replace(total,'MiB','') when instr(total,'GiB')>0 then replace(total,'GiB','')*1024 END AS total from sys.io_global_by_file_by_bytes WHERE FILE LIKE '%@@datadir%' AND instr(REPLACE(file, '@@datadir/', ''),'/')>0 )t GROUP BY database_name ORDER BY total_read_written DESC;
TOP SQL 統計
能夠按照執行時間,阻塞時間,返回行數等等維度統計top sql。
另外能夠按照時間篩選last_seen,能夠統計最近某一段時間出現過的top sql
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ; SELECT schema_name, digest_text, count_star, avg_timer_wait/1000000000000 AS avg_timer_wait, max_timer_wait/1000000000000 AS max_timer_wait, sum_lock_time/count_star/1000000000000 AS avg_lock_time , sum_rows_affected/count_star AS avg_rows_affected, sum_rows_sent/count_star AS avg_rows_sent , sum_rows_examined/count_star AS avg_rows_examined, sum_created_tmp_disk_tables/count_star AS avg_create_tmp_disk_tables, sum_created_tmp_tables/count_star AS avg_create_tmp_tables, sum_select_full_join/count_star AS avg_select_full_join, sum_select_full_range_join/count_star AS avg_select_full_range_join, sum_select_range/count_star AS avg_select_range, sum_select_range_check/count_star AS avg_select_range, first_seen, last_seen FROM performance_schema.events_statements_summary_by_digest WHERE last_seen>date_add(NOW(), interval -1 HOUR) ORDER BY max_timer_wait -- avg_timer_wait -- sum_rows_affected/count_star -- sum_lock_time/count_star -- avg_lock_time -- avg_rows_sent DESC limit 10;
須要注意的是,這個統計是按照MySQL執行一個事務消耗的資源作統計的,而不是一個語句,筆者一開始懵逼了一陣子,舉個簡單的例子。
參考以下,這裏是循環寫個數據的一個存儲過程,調用方式就是call create_test_data(N),寫入N條測試數據。
好比call create_test_data(1000000)就是寫入100W的測試數據,這個執行過程耗費了幾分鐘的時間,按照筆者的測試實例狀況,avg_timer_wait的維度,絕對是一個TOP SQL。
可是在查詢的時候,始終沒有發現這個存儲過程的調用被列爲TOP SQL,後面嘗試在存儲過程內部加了一個事物,而後就順利地收集到了整個TOP SQL.
所以說performance_schema.events_statements_summary_by_digest裏面的統計,是基於事務的,而不是某一個批處理的執行時間的。
CREATE DEFINER=`root`@`%` PROCEDURE `create_test_data`( IN `loopcnt` INT ) LANGUAGE SQL NOT DETERMINISTIC CONTAINS SQL SQL SECURITY DEFINER COMMENT '' BEGIN -- START TRANSACTION; while loopcnt>0 do insert into test_mrr(rand_id,create_date) values (RAND()*100000000,now(6)); set loopcnt=loopcnt-1; end while; -- commit; END
另一點比較有意思的是,這個系統表是爲數很少的支持truncate的,固然它在內部,也是在不斷收集的一個過程。
執行失敗的SQL 統計
一直覺得系統不會記錄執行失敗的\解析錯誤的SQL,好比想統計由於超時而執行失敗的語句,後面才發現,這些信息,MySQL會完整地記錄下來
這裏會詳細記錄執行錯誤的語句,包括最終執行失敗(超時之類的),語法錯誤,執行過程當中產生了警告之類的語句。用sum_errors>0 or sum_warnings>0去performance_schema.events_statements_summary_by_digest篩選一下便可。
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ; select schema_name, digest_text, count_star, first_seen, last_seen from performance_schema.events_statements_summary_by_digest where sum_errors>0 or sum_warnings>0 order by last_seen desc;
Index使用狀況統計
基於performance_schema.table_io_waits_summary_by_index_usage這個系統表,其統計的維度一樣是「按照某個索引查詢返回的行數的統計」。
能夠按照哪些索引使用最多\最少等狀況進行統計。
不過這個統計有一個給人潛在一個誤區:
count_read,count_write,count_fetch,count_insert,count_update,count_delete統計了某個索引上使用到索引的狀況下,受影響的行數,sum_timer_wait是累計在該索引上等待的時間。
若是使用到了該索引,可是沒有數據受影響(就是沒有DML語句的條件沒有命中數據),將count_***不會統計進來,可是sum_timer_wait會統計進來
這就存在一個容易受到誤導的地方,這個索引明明沒有命中過不少次,可是卻產生了大量的timer_wait,索引看到相似的信息,也不能貿然刪除索引。
等待事件統計
MySQL數據庫中的任何一個動做,都須要等待(必定的時間來完成),一共有超過1000個等待事件,分屬不懂的類別,每一個版本都不同,且默認不是全部的等待事件都啓用。
我的認爲等待事件這個東西,僅作參考,不具有問題的診斷性,即使是再優化或者低負載的數據庫,累計一段時間,某些事件仍舊會積累大量的等待事件。
這些事件的等待事件,不必定都是負面性的,好比事物的鎖等待,是在併發執行過程當中必然會生成的,這個等待事件的統計結果,也是累計的,單純的看一個直接的值,不具有任何參考意義。
除非按期收集,作差值計算,根據實際狀況,才具有參考意義。
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ; SELECT SUBSTRING_INDEX(NAME, '/', 1) as wait_type,COUNT(1) FROM performance_schema.setup_instruments GROUP BY 1 ORDER BY 2 DESC; SELECT event_name, count_star, sum_timer_wait FROM performance_schema.events_waits_summary_global_by_event_name WHERE event_name != 'idle' order by sum_timer_wait desc limit 100;
最後,須要注意的是,
1,MySQL提供的諸多的系統表(視圖)中的數據,單純的看這個值自己,由於它是一個累計值,我的以爲意義不大,尤爲是avg_***,須要結合多方面的綜合因素,作參考使用。
2,任何系統表的查詢,均可能對系統性能的自己形成必定的影響,不要再對系統可能產生較大負面影響的狀況下作數據的統計收集。
參考:
http://www.javashuo.com/article/p-ftpfghtr-bd.html
耐克的廣告,居然是這麼的煽情
你能從一片空白裏,看到可能嗎?有些人要看到證據,等有人作到了纔敢出手。但那些第一個行動的人,他們等過嗎?他們直接出手,無論有沒有人作到過。你能從一片空白裏,看到可能嗎?不等別人,出手即證實。