我們在做性能測試的目的是什么,就是要測出一個系統的瓶頸在哪里,到底是哪里影響了我們系統的性能,找到問題,然后解決它。當然一個系統由很多東西一起組合到一起,應用程序、數據庫、服務器、中中間件等等很多東西。那我們測試的時候上面這些東西里面任何一個環節都可能會出問題,都可能會影響我們系統的性能。這篇博客主要講下mysql數據庫咱們在做性能測試的時候應該監控什么東西,又有哪些需要優化的地方。
哪些東西會影響mysql的性能?
1.硬件
2.系統配置
3.數據庫表結構
4.SQL以及索引
硬件
硬件就指的是數據庫服務器的配置,服務器說白了就是一台電腦而已,如果電腦的配置高,cpu處理能力強,內存大,硬盤是ssd的,那肯定性能好。當然這種方式成本也是最高的,要花錢的嘛。
系統配置
系統配置一個指的是操作系統的配置,有一些操作系統的配置會影響mysql的性能,現在咱們大多數服務器都是用的linux服務器,linux上面一切東西都是基於文件的,mysql數據里面的表、數據等等都是文件存在磁盤上的。
linux系統有一個系統配置是文件打開的數量,默認是1024,也就是最多只能打開1024個文件,那在數據庫里面表比較多、並發大的情況下,這1024就不夠用了,要想獲取數據就得打開文件,但是打開文件的數量最多就1024個,就會導致有一些數據獲取不到,就得等待別的文件關閉之后,才能打開。那就要修改系統的配置,在/etc/security/limits.conf文件里面可以修改最大打開文件的數量。
還有一些mysql配置參數會影響mysql的性能。
sleep超時時間
mysql的連接數是提前配置好的,如果程序里面代碼寫的不好,有一些數據庫操作沒有及時關閉數據庫,那這個鏈接就不會釋放,會一直占用鏈接,這樣子並發大的情況下,就會導致數據庫連接數不夠用了,就連接不上數據庫了。mysql默認8小時不操作數據庫才會自動關閉鏈接,所以這個sleep的超時時間會影響mysql的性能。
獨立表空間設置
讀/寫進程數配置
在mysql5.5之后讀、寫的進程數是可以配置的。默認讀和寫的進程數都是4個。
當然我們都知道,人多好干活嘛。進程多就是干活的人多,具體配置根據cpu的核數和業務邏輯來配置這兩個值。
假如cpu是32核的,那么就是同時可以有32個進程在運行,就可以把這兩個值給調大。
假如說是系統是一個內容類的網站,大多數操作都是讀操作,那么就可以把讀的進程數設置大一點,寫的進程數設置的小一點。
怎么修改呢,找到mysql的配置文件,在[mysqld]節點下加入下面參數的即可
緩存配置
在說緩存配置之前咱們先了解清楚,計算機在處理任務的時候是怎么處理的,先從磁盤上讀取數據,然后放到內存里面,cpu去內存里面拿數據,然后處理。
在寫的時候正好相反,cpu處理完之后,把數據放到內存里面,內存再放到磁盤里。
那從上面,我們發現,如果數據直接從內存里面拿的話,那速度就快很多了,我們看下面的圖,讀1M的數據,內存里面比從磁盤上快多少。
從上面這個圖我們發現從內存里面讀數據比從磁盤里面取數據快了N倍。
那到mysql里面,如果取數據的時候,mysql先把一些數據緩存到內存里面的話,取數據直接從內存里面取不就快很多了。
咱們在說mysql緩存之前,先說下mysql在執行一條查詢語句的時候都做了什么。
從上面的圖我們發現,mysql是有兩個地方檢查了內存的。如果內存里面找到我們想要的數據,那么就不去磁盤上查詢數據了。那么這兩個緩存都是什么,怎么配置呢。
qcache配置
緩存完整的SELECT語句和查詢結果,當查詢命中緩存,MySQL會立刻返回結果,跳過解析、優化和執行階段。
查詢緩存會跟蹤系統中的每張表,如果這些表發生變化,那么和這張表相關的所有查詢緩存全部失效。
在檢查查詢緩存的時候,MySQL不會對SQL進行任何處理,它精確的使用客戶端傳來的查詢(select),只要字符大小寫,或者注釋有一點點不同,查詢緩存就認為是不同的查詢。
任何一個包含不確定的函數(比如now(),current_date())的查詢不會被緩存。
MySQL查詢緩存可以改善性能,但是在使用的時候也有一些問題需要注意:
開啟查詢緩存對於讀寫都增加了額外的開銷。對於讀,在查詢開始前需要先檢查緩存;對於寫,在寫入后需要更新緩存。
一般情況這些開銷相對較小,所以查詢緩存一般還是有好處的。但也要根據業務特征權衡是否需要開啟查詢緩存。
怎么配置呢,找到mysql的配置文件,在[mysqld]節點下加入下面參數的即可
innodb_buffer_pool配置
mysql里面還有一個緩存配置就是innodb_buffer_pool的配置,innodb是現在mysql的默認存儲引擎,存儲引擎說白了就mysql存數據的時候到底是怎么存的。
就是一個倉庫里面怎么擺放貨物的。
buffer pool是innodb存儲引擎帶的一個緩存池,查詢數據的時候,它首先會從內存中查詢,如果內存中存在的話,直接返回,從而提高查詢響應時間。
innodb buffer pool和qcache的區別是:qcacche緩存的是sql語句對應的結果集,buffer pool中緩存的是表中的數據。buffer pool一般設置為服務器物理內存的70%。
怎么配置呢,找到mysql的配置文件,在[mysqld]節點下加入下面參數的即可
mysql架構上的優化
讀寫分離
多點寫入
數據庫表結構優化
當然系統在設計表結構的時候,一般都是架構師和一幫開發已經把表結構設計好了,咱們沒達到那個級別架構上的東西咱也不懂,就在設計表結構的時候需要注意的一些東西。
mysql索引優化
索引是什么呢,就和字典的目錄一樣。有目錄了,那咱們查數據就快了。
最適合建索引的列是出現在where子句后面的列。
唯一索引的效果最好,因為是唯一的。
利用最左前綴。
索引並不是越多越好。
mysql索引有4種類型
1、普通索引
最普通的索引,所有列都可以加
create index index_name on table_name (col);
2、主鍵索引
建表的時候加的主鍵
3、組合索引
create index index_name on table_name (col,col2);
4、唯一索引
CREATE UNIQUE INDEX index_name ON table_name (column_name);
去除重復、冗余索引
因為每個開發的水平都不一樣,不可避免的的會出現一些重復索引的問題。那我們怎么來查找有一些冗余的索引呢。
就要借助percona-toolkit這個工具了,它里面有pt-duplicate-key-checker這個工具可以幫咱們找出來哪些表里面有冗余的索引,並給出修改索引的語句。
pt-duplicate-key-checker -uroot -pxxx -dxx#-u指的是用戶 -p是密碼 -d是數據庫
這個能幫咱們找出來重復的索引,那還有一些根本就沒有必要用的索引,雖然索引建立的並不是重復,但是實際上並沒用查詢語句用到它,怎么辦呢,percona-toolkit這個工具里還有一個工具是pt-index-usage,它可以讀取慢查詢日志,幫咱們找到那些沒用的索引。
pt-index-usage /opt/data/slow.log #后面是慢查詢日志
慢查詢日志
什么是慢查詢日志呢,它這個就是個神器了,對咱們測試特別有幫助,它會記錄執行時間長的sql語句,這樣咱們找問題的時候就比較方便了。
set global slow_query_log=on;#打開慢查詢日志 set global long_query_time=1;#設置記錄查詢超過多長時間的sql set global slow_query_log_file='/tmp/slow_query.log';#設置mysql慢查詢日志路徑,此路徑需要有寫權限 set global log_queries_not_using_indexes=ON; #設置沒有使用索引的sql記錄下來 SHOW VARIABLES LIKE '%slow%';#查看慢查詢配置
mysql記錄的日志里面,咱們看着比較不清晰,咱們使用pt-query-digest這個工具幫咱們解析慢查詢日志,它會把所有的sql的執行時間以及具體sql,執行了多少次都幫咱們統計出來。
下面是pt-query-digest的用法
pt-query-digest --filter='$event->{fingerprint} =~ m/^select/i' slow.log #查看包含select語句的慢查詢 pt-query-digest --since=12h slow.log #最近12小時的 pt-query-digest --since '2017-12-01 09:30:00' --until '2017-12-02 10:00:00' --filter='$event->{fingerprint} =~ m/^select/i' slow.log #指定時間段
如果想實時的獲取有沒有執行時間長的sql,用下面這個sql語句
select id,`user`,`host`,DB,command,`time`,state,info from information_schema.PROCESSLIST where TIME>=60;
explain
通過慢查詢日志我們可以找到有問題的sql語句,那我們怎么看這個sql哪有問題呢,就要使用explain了,只要在你要執行sql語句前面加上explain即可
all<index<range<ref<eq_ref<const,system sql執行type列里最差到最優
sql優化時候需要注意的
查詢條件使用索引列,排序使用索引列
避免select *,一般select * 都會造成全表掃描
盡量避免子查詢,MySQL 的子查詢執行計划一直存在較大的問題,雖然這個問題已經存在多年,但是到目前已經發布的所有穩定版本中都普遍存在,一直沒有太大改善。雖然官方也在很早就承認這一問題,並且承諾盡快解決,但是至少到目前為止我們還沒有看到哪一個版本較好的解決了這一問題。
事物
銀行存錢例子。
鎖
表級鎖、行級鎖。
SELECT * FROM information_schema.INNODB_TRX\G
mysql性能測試工具
mysqlslap是mysql自帶的一個性能測試工具。它可以模擬各種並發,以及使用哪種sql,生成多少數據,運行多久,產生報告。
常用的選項
--concurrency 並發數量,多個可以用逗號隔開 --engines 要測試的引擎,可以有多個,用分隔符隔開,如--engines=myisam,innodb --auto-generate-sql 用系統自己生成的SQL腳本來測試 --auto-generate-sql-load-type 要測試的是讀還是寫還是兩者混合的(read,write,update,mixed) --number-of-queries 總共要運行多少次查詢。每個客戶運行的查詢數量可以用查詢總數/並發數來計算 --debug-info 額外輸出CPU以及內存的相關信息 --number-int-cols 創建測試表的int型字段數量 --number-char-cols 創建測試表的chat型字段數量 --create-schema 測試的database --query 自己的SQL 腳本執行測試 --only-print 如果只想打印看看SQL語句是什么,可以用這個選項
下面是使用的例子
100並發,運行1000次,寫操作和讀操作都有,自動生成sql,int類型字段2個,char類型10個, mysqlslap -h127.0.0.1 -uroot -p123456 --concurrency=100 --auto-generate-sql --auto-generate-sql-load-type=mixed --engine=innodb --auto-generate-sql-add-autoincrement --number-int-cols=2 --number-char-cols=10 --number-of-queries=10 100並發,運行5000次,besttest這個數據庫上執行sql mysqlslap -h127.0.0.1 -uroot -p123456 --concurrency=100 --query='select * from stu;' -create-schema=besttest --engine=innodb --number-of-queries=5000 --debug-info 100並發,運行5000次,besttest這個數據庫上執行指定的sql文件 mysqlslap -h127.0.0.1 -uroot -p123456 --concurrency=100 --query=/tmp/besttest.sql -create-schema=besttest --engine=innodb --number-of-queries=5000 --debug-info