咱們在作性能測試的目的是什麼,就是要測出一個系統的瓶頸在哪裏,究竟是哪裏影響了咱們系統的性能,找到問題,而後解決它。固然一個系統由不少東西一塊兒組合到一塊兒,應用程序、數據庫、服務器、中中間件等等不少東西。那咱們測試的時候上面這些東西里面任何一個環節均可能會出問題,均可能會影響咱們系統的性能。這篇博客主要講下mysql數據庫我們在作性能測試的時候應該監控什麼東西,又有哪些須要優化的地方。mysql
1、哪些東西會影響mysql的性能?
- 1.硬件
- 2.系統配置
- 3.數據庫表結構
- 4.SQL以及索引
硬件
硬件就指的是數據庫服務器的配置,服務器說白了就是一臺電腦而已,若是電腦的配置高,cpu處理能力強,內存大,硬盤是ssd的,那確定性能好。固然這種方式成本也是最高的,要花錢的嘛。linux
系統配置
系統配置一個指的是操做系統的配置,有一些操做系統的配置會影響mysql的性能,如今我們大多數服務器都是用的linux服務器,linux上面一切東西都是基於文件的,mysql數據裏面的表、數據等等都是文件存在磁盤上的。sql
linux系統有一個系統配置是文件打開的數量,默認是1024,也就是最多隻能打開1024個文件,那在數據庫裏面表比較多、併發大的狀況下,這1024就不夠用了,要想獲取數據就得打開文件,可是打開文件的數量最多就1024個,就會致使有一些數據獲取不到,就得等待別的文件關閉以後,才能打開。那就要修改系統的配置,在/etc/security/limits.conf文件裏面能夠修改最大打開文件的數量。數據庫
1
2
3
|
vi /etc/security/limits.conf
* soft nofile 65536
* hard nofile 65536
|
還有一些mysql配置參數會影響mysql的性能。sublime-text
sleep超時時間
mysql的鏈接數是提早配置好的,若是程序裏面代碼寫的很差,有一些數據庫操做沒有及時關閉數據庫,那這個連接就不會釋放會一直佔用連接,這樣子併發大的狀況下,就會致使數據庫鏈接數不夠用了,就鏈接不上數據庫了。mysql默認8小時不操做數據庫纔會自動關閉連接,因此這個sleep的超時時間會影響mysql的性能。緩存
1
2
|
set global wait_timeout=600; 設置sleep的超時間,單位是秒
show variables like '%wait_timeout%'; 查詢超時時間
|
獨立表空間設置
1
2
|
set global innodb_file_per_table =ON; 設置獨立表空間打開
show variables like '%per_table%'; #查詢是否打開獨立表空間
|
讀/寫進程數配置
在mysql5.5以後讀、寫的進程數是能夠配置的。默認讀和寫的進程數都是4個。服務器
固然咱們都知道,人多好乾活嘛。進程多就是幹活的人多,具體配置根據cpu的核數和業務邏輯來配置這兩個值。架構
假如cpu是32核的,那麼就是同時能夠有32個進程在運行,就能夠把這兩個值給調大。併發
假如說是系統是一個內容類的網站,大多數操做都是讀操做,那麼就能夠把讀的進程數設置大一點,寫的進程數設置的小一點。函數
怎麼修改呢,找到mysql的配置文件,在[mysqld]節點下加入下面參數的便可
1
2
|
innodb_read_io_threads
=5 讀進程數
innodb_write_io_threads
=3 寫進程數
|
緩存配置
在說緩存配置以前我們先了解清楚,計算機在處理任務的時候是怎麼處理的,先從磁盤上讀取數據,而後放到內存裏面,cpu去內存裏面拿數據,而後處理。
在寫的時候正好相反,cpu處理完以後,把數據放到內存裏面,內存再放到磁盤裏。
那從上面,咱們發現,若是數據直接從內存裏面拿的話,那速度就快不少了,咱們看下面的圖,讀1M的數據,內存裏面比從磁盤上快多少。
從上面這個圖咱們發現從內存裏面讀數據比從磁盤裏面取數據快了N倍。
那到mysql裏面,若是取數據的時候,mysql先把一些數據緩存到內存裏面的話,取數據直接從內存裏面取不就快不少了。
我們在說mysql緩存以前,先說下mysql在執行一條查詢語句的時候都作了什麼。
從上面的圖咱們發現,mysql是有兩個地方檢查了內存的。若是內存裏面找到咱們想要的數據,那麼就不去磁盤上查詢數據了。那麼這兩個緩存都是什麼,怎麼配置呢。
qcache配置
- 緩存完整的SELECT語句和查詢結果,當查詢命中緩存,MySQL會馬上返回結果,跳過解析、優化和執行階段。
- 查詢緩存會跟蹤系統中的每張表,若是這些表發生變化,那麼和這張表相關的全部查詢緩存所有失效。
- 在檢查查詢緩存的時候,MySQL不會對SQL進行任何處理,它精確的使用客戶端傳來的查詢(select),只要字符大小寫,或者註釋有一點點不一樣,查詢緩存就認爲是不一樣的查詢。
- 任何一個包含不肯定的函數(好比now(),current_date())的查詢不會被緩存。
- MySQL查詢緩存能夠改善性能,可是在使用的時候也有一些問題須要注意:
開啓查詢緩存對於讀寫都增長了額外的開銷。對於讀,在查詢開始前須要先檢查緩存;對於寫,在寫入後須要更新緩存。
通常狀況這些開銷相對較小,因此查詢緩存通常仍是有好處的。但也要根據業務特徵權衡是否須要開啓查詢緩存。
怎麼配置呢,找到mysql的配置文件,在[mysqld]節點下加入下面參數的便可
1
2
3
4
5
6
7
8
|
query_cache_size
= 200M
分配給查詢緩存的總內存,通常建議不超過256M
query_cache_limit
= 1M
這個選項限制了MySQL存儲的最大結果。若是查詢的結果比這個大,那麼就不會被緩存。
下面是查看qcache的狀態的語句
SHOW VARIABLES LIKE '%query_cache%';#查看qcache狀態
|
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]節點下加入下面參數的便可
1
2
3
4
5
|
innodb_buffer_pool_size=50M #Innodb_buffer_pool的大小
innodb_buffer_pool_dump_now=on #中止MySQL服務時,InnoDB將InnoDB緩衝池中的熱數據保存到本地硬盤。
innodb_buffer_pool_load_at_startup =on #啓動MySQL服務時,MySQL將本地熱數據加載到InnoDB緩衝池中。
SHOW VARIABLES LIKE '%innodb_buffer_pool%';#查看buffer_pool的大小
|
mysql架構上的優化
讀寫分離
多點寫入
數據庫表結構優化
固然系統在設計表結構的時候,通常都是架構師和一幫開發已經把表結構設計好了,我們沒達到那個級別架構上的東西咱也不懂,就在設計表結構的時候須要注意的一些東西。
mysql索引優化
索引是什麼呢,就和字典的目錄同樣。有目錄了,那我們查數據就快了。
最適合建索引的列是出如今where子句後面的列。
惟一索引的效果最好,由於是惟一的。
利用最左前綴。
索引並非越多越好。
mysql索引有4種類型
一、普通索引
最普通的索引,全部列均可以加
1
|
create index index_name on table_name (col);
|
二、主鍵索引
建表的時候加的主鍵
三、組合索引
1
|
create index index_name on table_name (col,col2);
|
四、惟一索引
1
2
|
CREATE UNIQUE INDEX index_name
ON table_name (column_name);
|
去除重複、冗餘索引
由於每一個開發的水平都不同,不可避免的的會出現一些重複索引的問題。那咱們怎麼來查找有一些冗餘的索引呢。
就要藉助percona-toolkit這個工具了,它裏面有pt-duplicate-key-checker這個工具能夠幫我們找出來哪些表裏面有冗餘的索引,並給出修改索引的語句。
1
|
pt
-duplicate-key-checker -uroot -pxxx -dxx#-u指的是用戶 -p是密碼 -d是數據庫
|
這個能幫我們找出來重複的索引,那還有一些根本就沒有必要用的索引,雖然索引創建的並非重複,可是實際上並沒用查詢語句用到它,怎麼辦呢,percona-toolkit這個工具裏還有一個工具是pt-index-usage,它能夠讀取慢查詢日誌,幫我們找到那些沒用的索引。
1
|
pt-index-usage /opt/data/slow.log #後面是慢查詢日誌
|
慢查詢日誌
什麼是慢查詢日誌呢,它這個就是個神器了,對我們測試特別有幫助,它會記錄執行時間長的sql語句,這樣我們找問題的時候就比較方便了。
1
2
3
4
5
6
7
|
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的用法
1
2
3
|
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語句
1
|
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,生成多少數據,運行多久,產生報告。
經常使用的選項
1
2
3
4
5
6
7
8
9
10
11
|
--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語句是什麼,能夠用這個選項
|
下面是使用的例子
1
2
3
4
5
6
7
8
|
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
|