12 mysql效能抖動
sql語句為什麼變」慢」了
在介紹wal機制時,innodb在處理更新語句的時候,只做了寫日誌這乙個磁碟操作,就是redo log,在更新記憶體寫完redo log之後,就返回客戶端成功。
當記憶體資料頁和磁碟資料頁內容不一致的時候,稱這個記憶體頁為」髒頁」,記憶體資料寫入磁碟後,記憶體和磁碟上的資料頁的內容一致,稱為」乾淨頁」。
平時執行很快的更新操作,其實就是在寫日誌和記憶體,而mysql偶爾」抖」一下的那個瞬間,可能就是在刷髒頁(flush)。
觸發資料庫的flush
--1 innodb的redo log寫滿了,這時候系統會停止所有更新操作,把checkpoint往前推進,redo log留出空間可以繼續寫。
--2 系統記憶體不足,當需要新的記憶體頁,而記憶體不夠用的時候,就要淘汰一些資料頁,空出記憶體給別的資料頁使用。如果淘汰的是髒頁,就要先將髒頁寫盤
--3 mysql認為系統」空閒」的時候,也要找時間,只要有機會就刷一點」髒頁」
--4 mysql正常關閉的時候,mysql會把所有記憶體的髒頁都flush到磁碟上。
每個資料頁有兩種狀態
--一種是在記憶體裡,記憶體裡有肯定是正確的結果,直接返回。
--另一種是記憶體裡沒有資料,就可以肯定資料檔案上是正確的結果,讀入記憶體後返回。
第一種」redo log寫滿了,要flush髒頁」,這種情況innodb要盡量避免,如果出現這種情況,整個系統就不能再接受更新了,所有的更新就必須堵住,從監控上看,更新數為0.
第二種」記憶體不夠用了,要先將髒頁寫到磁碟」,這種情況其實是常態,innodb用緩衝池(buffer pool)管理記憶體,緩衝池的記憶體頁有三種狀態
--1 還沒有使用的
--2 使用了並且是乾淨頁
--3 使用了並且是髒頁
innodb是如何區分乙個頁是髒頁還是乾淨頁呢?在每個資料頁的頭部有lsn,8個位元組,每次修改都會變大,對比這個lsn跟checkipoint的lsn,比checkpoint小的一定是乾淨頁。
innodb的策略是盡量使用記憶體,因此對於乙個長時間執行的庫來說,未被使用的頁會很少。
當要讀入的資料不在記憶體時就必須要緩衝池中申請乙個資料頁,這時候只能把最久不使用的資料頁從記憶體中淘汰掉,如果要淘汰的是乙個乾淨頁,就直接釋放出來復用,如果是髒頁就必須將髒頁刷到磁碟,變成乾淨頁後才能復用。
但是出現下面的情況會明顯影響效能
--1 乙個查詢要淘汰的髒頁個數太多,會導致查詢的響應時間明顯變長
--2 日誌寫滿,更新全部堵住,寫效能為0,對敏感業務來說,是明顯不能接受的。
所以,innodb需要有控制髒頁比例的結構來避免這樣的情況
innodb刷髒頁的控制策略
要正確的告訴innodb主機的io能力,這樣innodb才能知道需要全力刷髒頁的時候,可以多塊,引數innodb_io_capacity,這個值建議設定磁碟的iops,磁碟的iops可以通過fio這個工具來測試,下面的語句用來測試磁碟隨機讀寫的命令
fio -filename=$filename -direct=1 -iodepth 1 -thread -rw=randrw -ioengine=psync -bs=16k -size=500m -numjobs=10 -runtime=10 -group_reporting -name=mytest
引數innodb_max_dirty_pages_pct是髒頁比例上限,預設75%,innodbui根據當前的髒頁比例,算出乙個範圍在0~100直接的數字
innodb每次寫日誌有乙個序號,當前寫入的需要跟checkpoint對應的序號之間的差值,假設為n,innodb會根據這個n算出乙個範圍在0~100之間的數字,這個n約大,算出的值就越大。
要盡量避免業務端感受到mysql」抖」一下,就要合理的設定innodb_io_capacity的值,並且平時要多關注髒頁比例,不要經常接近75%。
髒頁比例
mysql> select variable_value into @a from global_status where variable_name = 'innodb_buffer_pool_pages_dirty';select variable_value into @b from global_status where variable_name = 'innodb_buffer_pool_pages_total';select @a/@b;
([email protected]:3306) [information_schema]> select @a/@b;+------------------------+
| @a/@b |
| 0.00004577729852902281 |
1 row in set (0.00sec)
([email protected]:3306) [information_schema]> show global status like 'innodb_buffer_pool_pages_dirty';+--------------------------------+-------+
| variable_name | value |
| innodb_buffer_pool_pages_dirty | 40 |
1 row in set (0.00sec)
([email protected]:3306) [information_schema]> show global status like 'innodb_buffer_pool_pages_total';+--------------------------------+--------+
| variable_name | value |
| innodb_buffer_pool_pages_total | 393208 |
1 row in set (0.00sec)
([email protected]:3306) [information_schema]> show variables like 'innodb_io_capacity';+--------------------+-------+
| variable_name | value |
| innodb_io_capacity | 400 |
1 row in set (0.00sec)
([email protected]:3306) [information_schema]> show variables like 'innodb_max_dirty_pages_pct';+----------------------------+-------+
| variable_name | value |
| innodb_max_dirty_pages_pct | 60 |
在看乙個策略
一旦乙個查詢請求需要在執行過程中先flush掉乙個髒頁時,這個查詢就可能比平時慢了,而mysql中的乙個機制可能讓你的查詢會更慢,
在準備刷乙個髒頁的時候,如果這個資料頁旁邊的資料剛好是髒頁,就會把這個」鄰居」也帶著一起刷掉;而這個把鄰居一起的邏輯還可以繼續蔓延,也就是對於每個鄰居資料頁,如果跟它相鄰的資料頁也還是髒頁的話,也會被放到一起刷
在innodb中,引數innodb_flush_neighbors用來控制這個行為,值為1的時候有上述刷鄰的行為,為0的時候表示不找自己鄰居,只刷自己。
這個找鄰的優化在機械硬碟時代還是很有意義,可以減少很多隨機的io,機械硬碟的iops一般只有幾百,相同的邏輯操作減少隨機io就意味著系統效能的大幅度提公升,
而如果使用ssd這類iops較高的裝置的話,建議把該引數設定為0,在mysql 8.0,引數innodb_flush_neighbors預設為0.
思考題乙個記憶體未128gb,innodb_io_capacity設定為20000的大規格例項,正常建議會將redo log設定為4個1gb檔案,但是如果在配置的時候不慎將redo log設定成了1個100m的檔案,會發生什麼情況?又為什麼會出現這樣的情況呢?
12 mysql簡單優化
檢視所有運 況,加global為執行至今 show status 檢視經歷多少查詢 show global status like com select 檢視經歷多少插入 show global status like com insert 查詢伺服器執行多長時間 show global statu...
12 mysql匯入資料
1 mysql命令匯入 語法 mysql u root p passwd runoob.sql 2 source命令匯入 source aa.sql 3 使用load data匯入資料 mysql 中提供了load data infile語句來插入資料。以下例項中將從當前目錄中讀取檔案 dump.t...
12 mysql中的游標
查詢語句可能查詢出多條記錄,在儲存過程和函式中使用游標來逐條讀取查詢結果集中的記錄。有些書上將游標稱為游標。游標的使用包括宣告游標 開啟游標 使用游標和關閉游標。游標必須宣告在處理程式之前,並且宣告在變數和條件之後。游標可以模擬為陣列內部中的迴圈指標。declare cursor name curs...