性能測試之MySQL的監控和調優


一, 影響MySQL性能因素

CPU、內存, 網卡流量, 磁盤IO, 數據庫參數配置, SQL查詢速度等

CPU: 64位的CPU一定要工作在64位的系統下,如果並發量大的話,就需要選擇更多核心的CPU來提高吞吐量,對於並發比較高的 場景,CPU的數量比頻率重要對於密集型場景和復雜SQL,則CPU頻率越高越好

內存: 容量越多越好,但對性能影響有限,因為並不能無限的增加性能 主頻則選擇服務器主板可支持的最高頻率最好

I/O子系統: PCIe(pcie接口固態硬盤,性能最好1560MBps) -> SSD(sata接口固態硬盤560MBps) ->Raid10(磁盤陣列) ->機械磁盤 ->SAN(網絡存儲)

http://www.21ic.com/app/analog/201906/898183.htm

二,SQL介紹

SQL(Structure Query Language)是數據庫操作的的核心語言

DDL(Data Definition Languages)語句:即數據庫定義語句,用來創建數據庫中的表、索引、視圖、存儲過程、觸發器等,常用的語句關鍵字有:CREATE,ALTER,DROP,TRUNCATE,COMMENT,RENAME。

DML(Data Manipulation Language)語句:即數據操縱語句,用來查詢、添加、更新、刪除等,常用的語句關鍵字有:SELECT,INSERT,UPDATE,DELETE,MERGE,CALL,EXPLAIN PLAN,LOCK TABLE,包括通用性的增刪改查。

DCL(Data Control Language)語句: 即數據控制語句,用於授權/撤銷數據庫及其字段的權限(DCL is short name of Data Control Language which includes commands such as GRANT and mostly concerned with rights, permissions and other controls of the database system.)。常用的語句關鍵字有:GRANT,REVOKE。

TCL(Transaction Control Language)語句:事務控制語句,用於控制事務,常用的語句關鍵字有:COMMIT,ROLLBACK,SAVEPOINT,SET TRANSACTION。

 三,MySQL的連接數

MYSQL數據庫默認最大連接數是100,然而對於流量稍微大一點的論壇或網站這個連接數是遠遠不夠的,當並發數過大的時候會出現連接數不夠用,使得很多線程在等待其他連接釋放,會直接導致導致數據庫連接超時或者響應時間過長,所以需要調整最大連接數。show variables like '%max_connections%';

重新設置數據庫最大連接數 set global max_connections=200(全局的)

  設置完成后我們再看一下:

查詢數據庫當前設置的最大連接數 show variables like '%max_connections%';

當發現數據庫連接池占滿,或者應用程序日志報錯鏈接數據庫失敗的時候,我們就需要查看連接數和設置連接數,如何判斷連接數占滿了呢?有兩種方法

1,查當前的連接數和最大的連接數,如果兩者相等就是被占滿了

show gloable status like '%max_used_connections%';查看歷史使用的最高連接數

注意這個歷史數據不會降低,如這次使用的連接數是20,是以往的最高紀錄,就被記錄為歷史最高連接數,下次使用是100,那么就被記錄為歷史最高連接數為100,不斷的去擴大,不會縮減,那我們如何判斷數據庫連接池被占滿呢?請下下面第二種方法

2,查看線程占用的連接數和數據庫連接池的配置:

查看線程占用的連接數:show status like 'thread%';如圖:

Threads_cached:   #表示mysql管理的線程池中還有多少可以被復用的資源

Threads_connected  # 打開的連接數  如果這數據和當前的最大的連接數一致,那么就意味着連接被占滿了

Threads_created  # 表示創建過的線程數

Threads_running  # 激活的連接數,這個數值一般遠低於connected數值, # 准確的來說,Threads_running是代表當前並發數 。一般做壓測的時候,這個數據和Threads_connected是差不多的

同時還要結合數據庫連接池的配置

那么這個最大連接數和我們所說的數據庫連接池有什么關系呢?如圖說明:

 

 注意:這里的連接池是指應用程序中配置的連接池,最大連接數是數據庫本身能支持的連接數量

四,MySQL緩存

數據庫屬於 IO 密集型的應用程序,其主要職責就是數據的管理及存儲工作。而我們知道,從內存中讀取一個數據庫的時間是微秒級別,而從一塊普通硬盤上讀取一個IO是在毫秒 級別,二者相差3個數量級。所以,要優化數據庫,首先第一步需要優化的就是 IO,盡可能將磁盤IO轉化為內存IO。

緩存分為兩個維度 查詢緩存Query cache 存儲引擎InnoDB_Buffer_Pool

查詢緩存----------->

查詢緩存Query cache 查詢緩存會緩存完整的SELECT查詢結果,當查詢命中緩存時MySQL會將結果立刻返回,直接跳過了解析、優化和執行階段。當然,Query Cache 也有一個致命的缺陷,那就是當某個表的數據有任何變化,都會導致所有引用了該表的select語句在Query Cache 中的緩存數據失效。所以,當我們的數據變化非常頻繁的情況下,使用Query Cache 可能會得不償失。因此,應用程序不需要關心MySQL是通過緩存查詢出的結果還是實際執行過SQL語句返回的結果,因為這兩種結果是完全相同的 從前面的數據庫執行過程圖中可以看到,執行一條SQL查詢語句會先查詢該語句是否 存在於緩存中,需要注意的是當語句中的字符大小寫或注釋只要有一點點的不同,查詢緩存就會被認為是不同的查詢,導致無法命中查詢緩存。另外,對於不確定的 函數,如:now()、current_date()等這種查詢都不會被緩存 既然查詢緩存的有可以改善性能的優點,自然也有自己的缺點,主要體現在當開啟了查詢緩存時對於讀寫操作都增加了額外的開銷。相對於讀,再查詢開始前需要先檢查緩存,而對於寫,則是當寫入數據后需要更新緩存。

怎么設置緩存的大小呢?

Query cache的參數 查詢緩存參數,在mysql配置文件中添加,linux下為my.cnf,windows下為my.ini:

# 1.是否開啟查詢緩存,具體選項是0(OFF),1(ON)和2(DEMAND) , 添加--->query_cache_type = 1

# 2.分配給查詢緩存的總內存,一般建議不超過256M ,添加-->query_cache_size = 128M

# 3.表示單個結果集所被允許緩存的最大值,結果比這個大,就不會被緩存,添加--->query_cache_limit = 1M (注意配置完后要重新啟動數據庫

#4.分配內存塊時的最小單位大小;最合適的大小和應用程序查詢結果的平均大小直接相關 query_cache_min_res_unit=4096

#5.如果某個數據表被鎖住,是否仍然從緩存中返回數據,默認是OFF,表示仍然可以返回 query_cache_wlock_invalidate=OFF,這里如果是on表示不從緩存中返回數據,意味着緩存被清除

Show variables like '%query_cache%';

如果磁盤有數據更新,如何保證查詢緩存中的數據是最新的呢?

查看緩存命中率:show status  like 'Qcache%'

 

 查看緩存結果:show status like ‘Qcache%’

Qcache_free_blocks:表示查詢緩存中目前還有多少剩余的blocks,如果該值顯示較大,則說明查詢緩存中的內存碎片過多了,可能在一定的時間進行整理

Qcache_free_memory:查詢緩存剩余的內存大小,通過這個參數可以知道當前系統的查詢內存是否夠用,可以根據實際情況做出調整

Qcache_hits:表示有多少次命中緩存。我們主要可以通過該值來驗證我們的查詢緩存的效果。數字越大,緩存效果越理想,注意這個值越大越好

Qcache_inserts: 表示多少次未命中然后插入,意思是新來的SQL請求在緩存中未找到,不得不執行查詢處理,執行查詢處理后把結果insert到查詢緩存中。這樣的情況的次數越多,表示查詢緩存應用到的比較少,效果也就不理想。當然系統剛啟動后,查詢緩存是空的,這很正常。注意這值越小越好

Qcache_lowmem_prunes:該參數記錄有多少條查詢因為內存不足而被移除出查詢緩存。通過這個值,用戶可以適當的調整緩存大小,這值比較大說明緩存配置小了,就要去my.cnf中配置query_cache_size的值了

Qcache_not_cached: 表示因為query_cache_type的設置而沒有被緩存的查詢數量,如果這個值比較大,說明有可能是緩存最大塊的分配小了,可以將query_cache_limit調大后進行驗證 

Qcache_queries_in_cache:當前緩存中緩存的查詢數量 Qcache_total_blocks:當前緩存的block數量

存儲引擎緩存-------------->(了解就行,一般調優都是查詢緩存)

存儲引擎層-innodb buffer pool  

buffer pool是innodb存儲引擎帶的一個緩存池,查詢數據的時候,它首先會從內存中查詢,如果內存中存在的話,直接返回,從而提高查詢響應時間;

innodb buffer pool和qcache的區別是:

qcacche緩存的是sql語句對應的結果集,

buffer pool中緩存的是表中的索引,數據,插入數據時的緩沖。Buffer pool是設置的越大越好,一般設置為服務器物理內存的70%。

innodb buffer pool性能調優重要的一個參數,默認8M:

innodb_buffer_pool_size = 8M # 大小

在my.cnf中設置: innodb_buffer_pool_size = 512M

show VARIABLES like '%innodb_buffer%';

 

 五,事務和鎖

事物 :一個最小的不可再分的工作單元;通常一個事務對應一個完整的業務(例如銀行賬戶轉賬業務,該業務就是一個最小的工作單元)  一個完整的業務需要批量的sql(insert、update、delete)語句共同聯合完成

一個事物:

start transaction

update table set id=1 where name = test

select * from table where id =1

commit;  只有執行了commit才能提交

兩個事物:

update table set id=1 where name = test

select * from table where id =1

注:兩個事物同時並行操作同一張表

有事務必然有鎖,如事務中的update和insert行為

鎖 MySQL大致可歸納為以下3種鎖:

表級鎖:開銷小,加鎖快;不會現死鎖;鎖定粒度大,發生鎖沖突的概率最高,並發度最低。一般sql語句中不加where條件或者where條件不是索引,就會鎖表

行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖沖突的概率最低,並發度也最高。如果不會鎖表,那么就要鎖行,where條件有索引就要行鎖

頁面鎖:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,並發度一般

表鎖: Update Score set id = xx

行鎖: Update Score set id = xx where Stu_id=xx; 注:InnoDB這種行鎖實現特點意味着:只有通過索引條件檢索 數據,InnoDB才使用行級鎖,否則,InnoDB將使用表鎖! 

共享鎖: 共享鎖又叫做讀鎖,所有的事務只能對其進行讀操作不能寫操作,加上共享鎖后在事務結束之前其他事務只能再加共享鎖

排他鎖: 若某個事物對某一行加上了排他鎖,只能這個事務對其進行讀寫,在此事務結束之前,其他事務不能對其進行加任何鎖,其他進程可以讀取,不能進行寫操作,需等待其釋放 InnoDB引擎默認的修改數據語句,update,delete,insert都會自動給涉及到的數據加上排他鎖,

select語句默認不會加任何鎖類 型,如果加排他鎖可以使用select ...for update語句 加共享鎖可以使用select ... lock in share mode語句。

所以加過排他鎖的數據行在其他事務種是不能修改數據的,也不能通過for update和lock in share mode鎖的方式查詢數據,但可以直接通過select ...from...查詢數據,因為普通查詢沒有任何鎖機制。

死鎖:  死鎖是指兩個或者多個事務在同一資源上互相占用,並且請求鎖定對方占用的資源,從而導致死循環的現象

START TRANSACTION;

UPDATE Score set grade = 99 where id =7;

select SLEEP(10);

UPDATE Score set grade = 76 where id =8;

查看是否死鎖: show engine innodb status;(把查詢的日志寫到文件中查比較方便,一般日志里有dblock等字樣) 結果寫文件:mysql -u root -p --execute="show engine innodb status \G" > /tmp/mysql.log

查詢死進程 show processlist;  壓測過程出,這里查到死鎖后,直接用kill 殺掉先釋放了,再解決問題

KILL xxxx; 多線程並發才有可能死鎖 避免交叉加鎖 減少涉及的表,表聯接會大大增加鎖范圍

 

 

六,Mysql慢查詢

開啟慢查詢日志,可以讓MySQL記錄下查詢超過指定時間的語句,通過定位分析性能的瓶頸,才能更好的優化數據庫系統的性能。開始慢查詢的三個參數:

slow_query_log 慢查詢開啟狀態

slow_query_log_file 慢查詢日志存放的位置(這個目錄需要MySQL的運行帳號的可寫權限,一般設置為MySQL的數據存放目錄)

long_query_time 查詢超過多少秒才記錄 慢查詢開啟方法

方法一命令行設置

Set log_output=table;

set global slow_query_log='ON';

set global long_query_time=1; 

 

select * from mysql.slow_log; 查看慢查詢(前提是開啟了慢查詢)

 

方法二,配置文件設置:

修改配置文件my.cnf

在[mysqld]下的下方加入

log_output=table 表示存到表里

slow_query_log = 1 或 on

long_query_time = 1 設置大於1秒的記錄

查看慢查詢相關參數:

show variables like 'slow_query%'; #查詢是否開啟

show variables like 'long_query_time'; #查詢超時時間

show variables like '%log_output%';#查詢存儲類型

查看慢查詢sql有三種類型:

運行慢查詢sql

SELECT SLEEP(3);

查看慢sql

SELECT * FROM mysql.slow_log;

七,Explain 執行計划---->表示預處理,並不會真的執行

Explain :

該命令是查看查詢優化器如何決定執行查詢的主要方法

EXPLAIN select * from Score a JOIN class b on a.id = b.id where a.id in (SELECT b.id from Score a join class b on a.grade = b.grade where b.grade IN (SELECT a.grade from Score a)) GROUP BY a.stu_id order by b.id desc; Explain列解析:

Id: id相同由上向下執行,不同值越大優先級越高,越先被執行

select_type :示查詢中每個select子句的類型(簡單OR復雜)

Type :表示MySQL在表中找到所需行的方式,又稱“訪問類型” ALL, index, range, ref, eq_ref, const, system, NULL 從左到右,性能從最差到最好。 All MySQL將遍歷全表以找到匹配的行。 Index index類型只遍歷索引樹。 range:索引范圍掃描,對索引的掃描開始於某一點,返回匹配值域的行。 ref:使用非唯一索引掃描或者唯一索引的前綴掃描,返回匹配某個單獨值的記錄行。eq_ref類似ref,區別就在使用的索引是唯一索引 const,system,當MySQL對查詢某部分進行優化,並轉換為一個常量時,使用這些類型訪問 NULL,MySQL在優化過程中分解語句,執行時甚至不用訪問

possible_keys :指出MySQL能使用哪個索引在表中找到記錄,查詢涉及到的字段上若存在索引

Key :顯示MySQL在查詢中實際使用的索引,若沒有使用,顯示為NULL

key_len 表示索引中使用的字節數,可計算查詢中使用的索引的長度

possible_keys 指出MySQL能使用哪個索引在表中找到記錄,查詢涉及到的字段上若存在索引

Ref 表示表的連接匹配條件,即哪些列或常量被用於查找索引列上的值

Rows 表示根據表統計信息及索引選用情況,估算的找到所需的記錄所需要讀取的行數

Extra 包含不適合在其他列中顯示但十分重要的額外信息

a. Using index 該值表示相應的select操作中使用了覆蓋索引

b. Using where 表示mysql服務器將在存儲引擎檢索行后再進行過

c. Using temporary 表示MySQL需要使用臨時表來存儲結果集,常見於排序和分組查詢

d. Using filesort 無法利用索引完成的排序操作稱為“文件排序”

e. Using join buffer 改值強調了在獲取連接條件時沒有使用索引,並且需要連接緩沖區來存儲中間結果。出現該值可能需添加索引來優

f. Impossible where 這個值強調了where語句會導致沒有符合條件的行

h. Select tables optimized away 這個值意味着僅通過使用索引,優化器可能僅從聚合函數結果中返回一行

I. Index merges 當MySQL 決定要在一個給定的表上使用超過一個索引的時候,就會出現以下格式中的一個,詳細說明使用的索引以及合並的類型

八,優化

查詢性能優化-------->

1,減少IO次數:

IO永遠是數據庫最容易瓶頸的地方,這是由數據庫的職責所決定的,大部分數據庫操作中超過90%的時間都是 IO 操作所占用的,減少 IO 次數是 SQL 優化中需要第一優先考慮,也是收效最明顯的優化手段。

減少IO次數 IO永遠是數據庫最容易瓶頸的地方,這是由數據庫的職責所決定的,大部分數據庫操作中超過90%的時間都是 IO 操作所占用的,減少 IO 次數是 SQL 優化中需要第一優先考慮,當然,也是收效最明顯的優化手段。

2,降低 CPU 計算

除了 IO 瓶頸之外,SQL優化中需要考慮的就是 CPU 運算量的優化了。order by, group by,distinct … 都是消耗 CPU 的大戶(這些操作基本上都是 CPU 處理內存中的數據比較運算)。當我們的 IO 優化做到一定階段之后,降低 CPU 計算也就成為了我們 SQL 優化的重要目標。

MySQL優化基本原則--->

1、選取最適用的字段類型,盡量避免浪費

2、使用連接(JOIN)來代替子查詢(Sub-Queries)

3、使用聯合(UNION)來代替手動創建的臨時表

4、減少排序

5、禁用外鍵

6、避免大sql

7、保持事物的短小精悍

8、避免大批量更新

9、避免取過量數據,靈活使用limit

10、避免在SQL 語句中進行數學運算、函數計算、邏輯判斷等操作

11、避免OR

12、優先優化高並發的 SQL,而不是執行頻率低某些“大”SQL

13、盡可能對每一條運行在數據庫中的SQL進行explain

 14、任何地方都不要使用 select * from t ,用具體的字段列表代替“*”,不要返回用不到的任何字段。

15、使用索引查詢。 MySQL索引的建立對於MySQL的高效運行是很重要的,索引可以大大提高MySQL的檢索速度。索引分單列索引和組合索引。單列索引,即一個索引只包含單個列,一個表可以有多個單列索引,但這不是組合索引。組合索引,即一個索引包含多個列。創建索引時,你需要確保該索引是應用在 SQL 查詢語句的條件(一般作為 WHERE 子句的條件)。 索引也會有它的缺點:雖然索引大大提高了查詢速度,同時卻會降低更新表的速度,如對表進行INSERT、UPDATE和DELETE。因為更新表時,MySQL不僅要保存數據,還要保存一下索引文件。

 


免責聲明!

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



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