高性能mysql筆記

(一) mysql 架構

1.1 邏輯架構

在這裏插入圖片描述
第二層:查詢解析,分析,優化,緩存以及所有的內置函數(日期,時間,數學等等),以及所有的誇存儲引擎的功能:存儲過程、觸發器、視圖等
第三層:包含存儲引擎,存儲引擎是負責數據的存儲和提取的。存儲引擎都實現了同樣的接口,屏蔽了不同ing存儲引擎的差異。
存儲引擎API 的底層函數,用於執行"開始事務"或者"根據主鍵提取一行記錄"等操作
注意:存儲引擎不會去解析sql 1^1,不同存儲引擎間不互相通信,只是簡單響應上層服務器的請求
1_1 InnoDB 是一個例外,會解析外鍵定義,因爲mysql服務器本身沒有實現該功能

1.2 併發控制

  • 問題
    多個查詢需要在同一時刻修改數據
    類比郵件,如果兩封郵件同時到達同一個收件人服務器,入過不控制,會發生兩封郵件內容相互追加

  • 讀寫鎖
    寫操作: 加鎖(獨佔鎖),只能有一個線程在寫
    讀操作:只能在沒有寫鎖存在的情況下才能獲取(共享鎖),可多個線程讀
    :一個寫鎖或阻塞其他的寫鎖與讀鎖

  • 鎖粒度
    含義:鎖定的數據量越少,則系統的併發程度越高(比如jdk1.7 與jdk1.8 的hashmap 的實現區別)
    3.1表鎖(tabkle lock)
    寫操作對整張表加鎖(鎖開銷小),會同時阻塞其他用戶對該表的讀、寫操作
    3.2 行鎖(row lock)
    特點: 最大程度支持併發處理(鎖開銷最大)
    :行級鎖只在存儲引擎實現

    1.3 事務

  1. 含義
    指的是一組原子性的sql查詢,或者是說是一個獨立的工作單元(單元內的sql要麼都成功,要麼全部失敗)
  2. 事物特性以及隔離級別
    原子+一致+持久+隔離
  3. 隔離級別:
  • read uncommitted
  • read committed
  • repeatble read(mysql 默認的事務隔離級別)
  • serilizable (完全犧牲併發性,只能串行操作,隔離級別最高)
  1. 不考慮隔離性可能出現的問題:

詳細參見另一篇博客
https://blog.csdn.net/qq_36922927/article/details/89326635

  1. 死鎖
    含義:兩個或多個

  2. 事務日誌
    日誌:順序io
    磁盤io:是隨機io
    預寫日誌:

  3. mysql 中的事務

  • auto commit
  • set transaction isolation level (設置事務隔離級別)
  • 同一個事務中使用多種存儲引擎不可靠(事務是在存儲引擎中實現的)
  • 事務回滾,如果事務中包含非事務型表,那麼該表不會回滾,也不會報錯,可能有提示

1.4 多版本併發控制(MVCC)

Mysql,Oracle,PostgreSQL 等關係數據庫都實現了MVCC(無統一標準,實現機制可能不同)

  1. 含義:
  • 可理解爲是行級鎖的變種
  • 根據事務開始的時間不同,每個事物對同一張表,同一時刻看到的數據可能是不一樣的
  1. InnoDB 的MVCC
  • 兩個隱藏列,分別保存行的創建時間,行的過期時間(這裏的時間不是實際時間值,而是指版本號)
  • 事務開始時刻的系統版本號會作爲事務的版本號,用來和查詢到的每行記錄的版本號比較

InnodDB 在repeatable read 隔離級別下的curd 操作邏輯如下

  • select
    a. 只查找版本號\leq 當前事務版本號的行(也就是隻查找版本早於當前事務的數據行)
    查到的行 要麼是事務開始前存在的,要麼是自身插入或者修改過的
    b. 行的刪除版本要麼未定義,要麼大於當前事務版本號。這是確保事務讀取到的行,在事務開始之前未被刪除
  • insert
    爲新插入的行以當前系統版本號作爲行版本號
  • update
    插入一行新紀錄,保存當前系統版本號作爲行版本號,同時保存當前系統版本號到原來的行作爲刪除標識
table(id,col1,col2,col3)// 表定義
原行:
(1,a,b,c,1,) //最後兩列是版本號  // 假設當前系統版本號是100
// 事務開始時,取當前系統版本號作爲事務版本號,然後系統版本號自增
操作 update table set col1 =f where id=1;// 此事務版本號爲100 , 事務開始時,系統版本號自增爲101
結果:
新增一條行記錄:
(1,f,b,c,101,);//當前系統版本號101 作爲行標識(行版本號)
修改原記錄:當前系統版本號作爲刪除標誌
(1,a,b,c,1,101);// 

  • delete
    爲刪除的每一行保存當前系統版本號作爲行版本號

: InnoDB 的mvcc 只在Repeatable read ,read committed 這兩個事務級別下工作
read uncommitted 總是讀取最新的數據行,而不是符合當前事務版本的數據行
serializable:對所有讀取的行都加鎖

1.5 mysql的存儲引擎

  1. InnoDB
  • 設計用來處理大量的短期事務,短期事務大部分是正常提交的,很少被回滾
  • 性能和自動崩潰恢復特性,在非事務性存儲場景也很流行
  • 表基於聚簇索引(主鍵查詢性能很高,但是二級索引中必須包含主鍵列,如果主鍵列很大,那麼其他索引都會很大)
  1. MyIsAM
  • 全文索引,壓縮,空間函數
  • 不支持事務和行級鎖(只能表加鎖(這也是性能瓶頸所在))
  • 延遲更新索引
  • 壓縮表 (數據不再修改的數據表)
  • 執行表修復可能導致一些數據丟失
  1. 存儲引擎的選擇-
  • 除非需要用到innodb 不具備的特性,否則優先選擇innodb
  • 除非萬不得已,不要選擇混合的存儲影青
  • 事務,如果不需要事務,那麼可以選擇MyIsam
  • 備份:在線熱備份,innodb
  • 崩潰恢復:MyIsAm 崩潰後損壞概率比InnoDB高很多,而且恢復速度慢

一些場景:

  • 日誌型應用:對插入速度要求高,考慮MyISAM
  • 讀多寫少,如果不介意MyISAM 的崩潰恢復問題(這個問題可以在測試環境拔掉電源測試),可以選擇MyISAM
  • 訂單處理:支持事務是必要選項,INNODB

(二) 剖析mysql 查詢

2.1 服務器負載

含義:找出效率低下的查詢,定位和優化"壞"查詢,提高應用性能

工具:

  • 慢查詢日誌:找出代價高的查詢(慢查詢日誌開銷低,精度高)

  • 通用日誌:在查詢請求到服務器時進行記錄,所以不包含響應時間和執行計劃等重要信息

  • pt-query-digest:分析查詢日誌的工具,可以將慢查詢日誌生成剖析報告
    剖析報告示例:
    在這裏插入圖片描述參數解讀:

參數 含義
Rank 排名,越慢越靠前
Query ID 對查詢語句計算出的哈希指紋
V/M 方差均值比(離差指數),與查詢對應的執行時間正相關
Item 相關查詢的簡寫,至於那個? 是 替代了表名後面的分片標識(這裏的分片是什麼我暫時不清楚)

剖析報告後面還有詳細報告
在這裏插入圖片描述
頂部包含:查詢執行的頻率,平均併發度,以及查詢性能最差的一次執行在日誌文件中的字節偏移值
接着是直方圖:Query_time distribution,查詢時間分佈

2.2 剖析單條查詢

  1. show profile:MySql 5.1以後的版本引入(默認是禁用的)
SET profiling =1;

啓用後,在服務器上執行的所有sql語句都會測量其耗費的時間,其他一些查詢狀態變更的數據
當一條查詢提交到服務器時,此工具會記錄剖析信息到一張臨時表中,斌哥且給查詢賦予一個從1開始的整數標識符
執行:show profile ; 顯示剖析結果
mysql 默認的時間只會精確到兩位小數
但是 show frofile 是顯示了 7位小數,精度是很高的

在這裏插入圖片描述來查看下Query_Id=6 的查詢的具體數據

show profile for query 6;

在這裏插入圖片描述
發現並不是按照耗時時間排序的,我想知道的是耗時較多的是哪些步驟
以下步驟格式化輸出:

SET @query_id=6;
SELECT
	state,
	SUM(DURATION) AS Total_R,
	ROUND(
		100 * SUM(duration) / (
			SELECT
				SUM(duration)
			FROM
				information_schema.PROFILING
			WHERE
				QUERY_ID =@query_id
		),2)AS Pct_R,
COUNT(*) as Calls,
SUM(duration)/COUNT(*) as "R/Call"
from information_schema.PROFILING
where QUERY_ID=@query_id
GROUP BY STATE
ORDER BY Total_R DESC;

在這裏插入圖片描述以上是單表查詢,沒有發現特別耗時的條目。

  1. show status
    計數器,顯示某些活動如讀索引的頻繁程度,但無法給出消耗多少時間
    參數很多,以後用到再來細究
    在這裏插入圖片描述在這裏插入圖片描述:show status 會區分內存臨時表和磁盤臨時表
    這點在explain 中是不能區別的

    下圖中:
    磁盤臨時表:Created_tmp_disk_table 0個
    總的臨時表:Created_tmp_tables 6
    內存臨時表: 總的臨時表數-磁盤=6
    未使用索引的讀:Handler_read_rnd_next
    在這裏插入圖片描述

2.3 診斷間歇性問題

含義:間歇性問題是指系統偶爾停頓或者慢查詢

計數器表

爲了統計網站的訪問數

  1. 單獨的表來統計數據,只有一行數據
    那麼對於每一個想更新這一行的事務來說,這條記錄上都有一個全局的互斥鎖,變爲串行,併發性能堪憂
  2. 爲了提高把併發性能,可以設置多行
    預先設置100行,每個事務隨機選取一行來更新
    所有行數據累加即得最終結果

如果不想預先生成行,可以使用 on duplicate key
在這裏插入圖片描述
3. 如果爲了減少表數據的行數
可以使用定時任務,將數據統計到地0行,然後刪除其他行

加快alter table

alter table 操作可能導致服務停止,耗時
解決方案:

  1. 先在不提供服務的數據庫上進行alter 操作,完成後,和主庫切換
  2. “影子拷貝”,建立一張和源表無關的表,然後重命名,刪除操作來交換兩張表
  3. 不是所有的alter table 都會導致表重建,alter 對應的列即可
    在這裏插入圖片描述

在這裏插入圖片描述

索引基礎

B_Tree 索引

名字是Btree ,但是底層實現可能是B+,T_Tree 結構存儲這種索引
B_Tree:

  1. 所有值是按順序存儲的,每一個葉子到根的距離相同
  2. 指針實際上定義子節點頁中值得上限和下限
  3. 最終存儲引擎要麼找到對應的值,要麼不存在

如何能使用上索引

滿足最左原則即可

索引列必須按照建立索引的順序使用,不能跳過,如果跳過,那麼只能在跳過列之前的索引生效

. 如果不是按照索引的最左列開始查找,則無法使用索引
. 不能跳過索引列
. 如果有某個列的範圍查詢,則其右邊的列無法使用索引優化查詢

hash 索引(Memory 殷勤支持

hash 表實現
索引=hash 值+數據行的指針
注意:

  1. hash 索引只包含哈希值和行指針
  2. hash 索引數據不是按照索引值順序存儲,故無法用於排序
  3. hash 索引只支持等值查詢 =,IN(),<>
    不支持任何範圍查詢,例如where price》100
  4. 訪問hash 速度快,除非hash 衝突很多,如果有哈市衝突,存儲引擎必須便利鏈表的所有行指針,逐行進行比較
  5. 如果hash 衝突很多,一些索引維護操作的代價很高。刪除一行,需要遍歷對應hash 值鏈表的每一行,找到並刪除對應行的引用,衝突越多,代價越大

innodb 的自適應hash 索引:
innnodb 在察覺到某些索引使用率很高,自動在B-tree 上建立一層hash 索引,快速定位到節點

創建自定義hash 索引

比如:在存儲大量URL,根據URL查找,如果使用B+Tree 存儲URL,內容很大,可以存儲一個索引列(hash)

hash 列可以使用觸發器來在插入數據時,自動插入hash 值

在這裏插入圖片描述
在這裏插入圖片描述

空間數據索引(R-Tree)

可以用作地理數據存儲,無需前綴查詢,從所有維度來索引數據

全文索引

查找的是文本中的關鍵詞,而不是直接比較瑣索引的值

索引的優點

  1. 減少服務器需要掃描的數據量
  2. 避免排序和臨時表
  3. 將隨機io變爲順序IO

如果數據表數據小,全表掃描效率更高
中,大型表,索引非常有效
特大型表。建立和使用索引的代價隨之增長,可以使用分區技術查出需要的一組數據,而不是一條一條記錄的去匹配
在這裏插入圖片描述

聚簇索引

聚簇索引不是一種單獨的索引類型,而是一種數據存儲方式。具體細節依賴於實現方式,但是Innodb 的聚簇索引實際在同一個結構中保存了B-Tree索引和數據行。
數據行實際上存放在索引的葉子頁中。
“聚簇”表示數據和相鄰的減值緊湊的存放在一起。因爲無法同時把數據行存放在兩個不同的地方,所以一個表只能有一個聚簇索引
在這裏插入圖片描述聚集的優點:

  1. 相關數據存儲在一起,如電子郵箱實現時,可以將ID 來聚集數據,只需要從磁盤讀取少數數據也就能獲取某個用戶的全部郵件。如果不適用聚簇,可能每封郵件發生一次IO
  2. 數據訪問更加快(相對於非聚集索引)
  3. 使用覆蓋索引掃描的查詢可以直接使用葉節點的主鍵值
    缺點:

覆蓋索引

使用索引直接獲取列的數據,這樣不需要讀取數據行。如果一個索引包含(或者是覆蓋)所有要查詢的字段的值,稱之爲“覆蓋索引”
好處:

  1. 索引條目通常遠小於數據行大小,如果只需要讀取索引,那麼mysql 就會極大的減少數據訪問量
  2. 索引通常是按照列值順序存儲的(至少在單個頁內是如此)
  3. 一些存儲引擎如MyIsam,在內存中只緩存索引,數據則依賴操作系統來緩存,因此訪問數據需要一次系統調用

— 未完待續

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章