多版本併發控制(MVCC):
1、可以認爲是行級鎖的一個變種,但是很多情況下都避免了加鎖操作,不同引擎的實現方式不一樣
2、實現是通過保存數據在某個時間的快照來實現的。
3、Innodb中,是通過在每行記錄後面保存兩個隱藏的列來實現的。一個保存了行的創建時間,一個保存了行的過期時間(刪除時間)實際存儲的是系統的版本號。每開始一個新的事務,系統版本號都會自動遞增。事務開始時刻的版本號作爲事務的版本號,用來和查詢到的每行記錄的版本號比較。在REPEATABLE READ隔離級別下,MVCC具體操作:
(1)SELECT
只查找版本早於當前事務版本的數據行,這樣可以確保事務讀取的行是事務開始前就已經存在了的,要麼是事務自身插入的;行的刪除版本要麼未定義,要麼大於當前事務版本號。這樣可以確保事務讀取到的行,在事務開始之前未被刪除。
(2)INSERT
新插入的每一行數據保存當前系統版本號作爲行版本號
(3)DELETE
同INSERT
(4)UPDATE
保存檔當前版本號作爲行版本號,同時保存當前系統版本號到原來的行作爲行刪除標識
優點:保存這兩個額外的行號,使大多數讀操作都可以不加鎖。
缺點:每行需要額外的存儲空間,需要做更多的行檢查,以及額外的維護工作
只在REPEATEABLE READ 和 READ COMMITTED兩個隔離級別工作。
實現了一致性非鎖定,解決了併發下讀寫衝突的問題,採用無鎖,版本控制的方式.
數據庫引擎:
Innodb:(MySQL默認存儲引擎,親兒子,沒有特別需求,優先這個引擎)
MySQL體系結構
結構和常用的存儲引擎
.frm文件是用於記錄表結構的,存在所有存儲引擎中
MyISAM存儲引擎:
- 系統表和臨時表都是用的MyISAM(臨時表:在排序、分組操作中,當數量超過一定大小後,由查詢優化器建立的臨時表)
- MyISAM存儲引擎由MYD和MYI組成(還有一個。frm文件,這個文件每個存儲引擎都會產生,作用都是一樣的)
- 特性:
併發性與鎖級別
表損壞修復(check table tablename、repair table tablename)
表支持索引類型
表支持數據壓縮(myisampack),缺點:壓縮以後就無法修改了,優點:減少磁盤空間佔用,減少磁盤IO,從而提升查詢性能
限制:
5.0版本前,默認表爲4G,存儲大表要修改爲MAX_Row和AVG_ROW_LENGTH
5.0版本後默認支持256TB
MyIsam壓縮後,不能寫,只能讀
- 適用場景:非事務應用、只讀類應用、空間類應用
Innodb存儲引擎:
1.使用表空間進行數據存儲
innodb的鎖都是行鎖
索引是聚集索引,設置主鍵自增會好一些
事務沒有提交的時候,別的線程訪問的是通過undo.log的備份,所以看到的還是原來的數據
在mysql服務層可以加標記鎖 行級鎖主要在存儲引擎層實現
死鎖會自動處理,會回滾資源最小的那個事務
Innodb中的鎖:
- 行級鎖:共享鎖(讀鎖,允許多個事務讀一行數據)、排他鎖(寫鎖,同一時刻,只允許一個事務修改一行數據)
- 意向鎖:
意向共享鎖(讀鎖 IS LOCK):事務想要獲取一張表的幾行數據的共享鎖,事務給一個數據行加共享鎖前必須取得該表的IS鎖
意向排他鎖(寫鎖 IX LOCK):事務想要獲取一張表中幾行數據的排他鎖,事務在一個數據行加排他鎖前必須先獲得該表的IX鎖
(加意向鎖爲了表明某個事務正在鎖定一行或者將要鎖定一行數據,價值在於節約Innodb對於鎖的定位和處理性能,除了全表掃描以外,意向鎖不會阻塞)
- 鎖算法:
Record Lock: 單行記錄上的鎖
Gap Lock: 間隙鎖,鎖定一個範圍,並且鎖定記錄本身
Next-Key Lock:結合上面兩種鎖。,主要解決幻讀。
csv存儲引擎:
1、把csv文件作爲表來存儲
2、通常作爲數據交換的存儲表
Archive存儲引擎:
1、只支持insert和select,
2、緩存和行級鎖
Federated
1、本地數據庫訪問遠程數據庫,mysql現在默認是關閉的
Memory存儲引擎:
1、所有數據都保存在內存中,重啓後數據丟失,結構保留
2、場景:查找或映射表,緩存週期性聚合數據的結果,保存數據分析中的中間數據
3、支持hash索引,表級鎖,不支持BLOB或TEXT,每行長度固定,指定了VARCHAR實際會轉爲CHAR。
4、MySQL臨時表就是Memory,大小超出Memory後纔會轉化爲MYISAM表(臨時表只在單個連接可見,關閉連接後就不可見)
NDB集羣引擎
1、分佈式、容災、高可用
參數配置:內存、IO、安全三個方面
配置設置全局後,已存在的連接可能會沒有效果,需要斷開,然後重新再連接
內存配置都是給每個線程配置的,
而且有一些參數一定是4K的倍數
過大可能會導致mysql內存溢出
緩存數據,緩存索引,
myisqm的緩存只緩存索引。
mysql的系統表還是myisam
mysql事務日誌,是寫滿一個文件再寫入下一個文件(先寫入緩存區,然後再刷新到日誌文件裏面)
innodb每個默認頁的大小是16K
雙寫緩存
修改sqlmode的時候可能會導致原來能正常使用的sql應用失敗,因爲拒絕了一些不符合sql模式的語句,這些語句會執行失敗
如何選擇引擎:
- 大部分情況下選擇Innodb都是正確的選擇
- 不要選擇混合使用多種存儲引擎
- 除非需要用到某些Innodb不具備的特性,並且沒有其他辦法可以替代,否則都應該優先選擇Innodb引擎。
如果需要用到別引擎,考慮因素:
- 事務 :如果不需要事務,並且主要是SELECT和INSERT,那麼可以選擇MyISAM
- 備份
- 崩潰恢復
- 特有的特性
轉換表的搜索引擎:
- ALTER TABLE : alter talbe xxx ENGINE = Innodb(耗時,將源數據複製到新的表裏,複製期間可能佔用系統所有IO能力)
- 導出與導入:mysqldump,然後在文件中修改ENGINE類型
- 創建與查詢:創建新表,然後用insert和select來複制數據到新表裏面
mysql優化:
sql優化,數據庫結構設計影響性能最大
影響性能的常見問題
列太多,關聯表太多,多表查詢速度比較慢,
使用外鍵約束效率低,每次都要查詢是否滿足外鍵約束
性能優化順序:
- 數據庫結構設計和sql語句
- 數據庫存儲引擎的選擇和參數的優化(最好不要混合使用引擎,調整緩衝池大小等)
- 系統選擇及優化(操作系統選擇以及其參數設置)
- 硬件升級
數據庫設計對性能的影響(常見的):
1、過分的反範式化爲表建立太多的列(列太多)
2、過分的範式話造成太多的表關聯(關聯表太多)
3、在OLTP環境中使用不恰當的分區表 (分區表是指一個數據庫表的位置不是在同一個地方,多個地方有??)
4、使用外鍵保證數據的完整性
基準測試:定義:
基準測試是一種測量和評估軟件西性能指標的活動,用於建立某個時刻的性能基準,以便系統發生軟硬件變化時重新進行基準測試以評估變化對性能的影響(簡化了壓力的測試)
壓力測試:對真實的業務數據進行測試,獲得真實系統所能承受的壓力(需要針對不同主題,所使用的數據和查詢也是真實用到的)
基準測試:直接、簡單、易於比較,用於評估服務器處理能力(可能不關心業務邏輯,所使用的查詢和業務的真實性可以和業務環境沒關係)
基準測試目的:
- 建立MySQL服務器的性能基線(確定當前MySQL服務器運行狀況)
- 模擬比當前系統更高的負載,以找出系統擴展瓶頸(例如,增加數據庫併發,觀察QPS,TPS變化,確定併發量與性能最優的關係)
- 測試不同硬件、軟件和操作系統配置
- 證明信的硬件設備是否配置正確
如何進行基準測試:
- 對整個系統進行基準測試:(從系統入口測試,如web前端,app前端)
優點:能夠測試整個系統性能,包括web服務其緩存、數據庫等; 能反映出系統各個組件接口間的性能問題體現真實性能狀況
缺點:測試設計複雜,消耗時間長
- 單獨對MySQL進行基準測試
優點:測試設計簡單,耗時短
缺點:無法全面瞭解整個系統哦你的性能基線
常見的測試指標
- 單位時間內所處理的事務數(TPS
- 單位時間內所處理的查詢數(QPS
- 響應時間(平均響應時間、最小響應時間、最大響應時間、各時間愛你所佔百分比)
- 併發量:同時處理的查詢請求的數量(正在工作的併發操作數或同時工作的數量)
基準測試的步驟
計劃和設計基準測試:(考慮兩個問題:對整個系統還是某一組件;使用什麼樣的數據)
- 準備基準測試及數據收集腳本(CPU使用率、IO、網絡流量、狀態與計數器信息等)
- 運行基準測試
- 保存及分析基準測試結果(analyze.sh)
基準測試中容易忽略的問題
- 使用生產環境數據時只使用了一部分數據(使用數據庫完全備份來測試)
- 在多用戶場景中,只做了單用戶的測試(使用多線程併發測試)
- 在單服務器上測試分佈式應用(使用相同的架構進行測試)
- 反覆執行統一查詢(容易緩存命中,無法反應真實查詢性能)
基準測試工具:
mysqlslap
特點:
可以模擬服務器負載,並輸出相關統計信息
可以指定也可以自動生成查詢語句
常用參數說明:
--auto-generate-sql 由系統自動生成SQL腳本進行測試
--auto-generate-sql-add-autoincrement 在生成的表中增加自增id
--auto-generate-sql-load-type 指定測試中使用的查詢類型
--auto-generate-sql-write-number 指定初始化數據時生成的數據量
--concurrency 指定併發的線程數量
--engine 指定要測試表的存儲引擎,可以用逗號分割多個存儲引擎
--no-drop 指定不清理測試數據
--iterations 指定測試運行的次數
--number-of-queries 指定每一個線程執行的查詢數量
--debug-info 指定輸出額外的內存及cpu統計信息
--number-int-cols 指定測試表中包含的INT類型列的數量
--number-char-cols 指定測試表中哦你包含的varchar類型的數量
--create-schema 指定用於執行測試的數據庫的名字
--query 用於指定自定義SQL的腳本
--only-print 並不運行測試腳本,而是把生成的腳本打印出來
sysbench
常用參數:
--test 用於指定所要執行的測試類型,支持以下參數
Fileio 文件系統I/O性能測試
cpu cpu性能測試
memoey 內存性能測試
Oltp 測試要指定具體的lua腳本
Lua 腳本位於 /usr/share/sysbench/
性能優化介紹
數據庫結構優化介紹
影響數據庫性能的因素有很多:服務器硬件,操作系統,MySQL服務器配置
良好的數據庫邏輯設計和物理設計是數據庫獲得高性能的基礎:
例如:反範式化設計能加快一些語句的查詢速度,但是也可能會影響其他語句的性能。
數據庫結構化優化的目的:
1、減少數據冗餘(不是沒有,儘量減少)
2、儘量避免數據維護中出現更新,插入和刪除異常(一般通過範式化來避免)
插入異常:如果表中的某個實體隨着另一個實體而存在
更新異常:如果更改表中的某個實體的單獨屬性時,需要對多行進行更新
刪除異常:如果刪除表中的某一實體則會導致其他實體的消失
3、節約數據存儲空間
4、提高查詢效率
數據庫結構設計步驟:
1、需求分析:全面瞭解產品設計的存儲需求(存儲需求、數據處理需求、數據的安全性和完整性)
2、邏輯設計:設計數據的邏輯存儲結構(進行規劃設計,理清數據實體之間的邏輯關係,解決數據冗餘和數據維護異常)
3、物理設計:根據所使用的數據庫特點進行表結構設計(關係型、非關係型,選擇存儲引擎:Innodb)
4、維護優化:根據實際情況對索引、存儲結構等進行優化
數據庫設計範式:
1、目的:設計出沒有數據冗餘和數據維護異常的數據庫結構
2、第一範式:
數據庫表中的所有字段都只具有單一屬性
單一屬性的列是基本的數據類型所構成的
設計出來的表都是簡單的二維表
3、第二範式:
要求一個表中具有一個業務主鍵,也就是說符合第二範式的表中不能存在非主鍵列只對部分主鍵的依賴關係,簡言之:
如果主鍵是兩個,就不能通過主鍵的其中一個確定唯一數據
4、第三範式:
指每一個非主屬性既不部分依賴於也不傳遞依賴於業務主鍵,也就是在第二範式的基礎上消除了非主屬性對主鍵的傳遞依賴,簡言之:如果行中的其中一個字段,能通過非主鍵列唯一確定,那麼就不符合第三範式。
範式化:
優點:
可以儘量的減少數據冗餘(數據表更新快,體積小)
範式化的更新操作比反範式化更快
範式化的表通常比反範式化更小
缺點:
對於查詢需要對多個表進行關聯(如果這種查詢是經常的,會極大損耗性能)
更難進行索引優化
反範式化:
優點:
可以減少表的關聯
更好的進行索引優化
缺點:
存在數據冗餘及數據維護異常()
對數據的修改需要更多的成本(冗餘數據多)
一般在需求分析及邏輯分析時,先使用範式化設計,然後結合業務具體操作,進行反範式化改造。
案例:
結論:不能完全按照範式化的要求進行設計,需要考慮以後如何使用表
物理設計:
內容:
1、定義數據庫、表及字段的命名規範
2、選擇合適的存儲引擎
3、爲表中的字段選擇合適的數據類型
4、建立數據庫結構
定義數據庫、表及字段命名規範:
1、遵守可讀性原則
2、遵守表意性原則
3、遵守長名原則
合適的存儲引擎:
爲字段選擇合適的數據類型:
原則:
1、當一個列可以選擇多種數據類型時,應該優先考慮數字類型,其次是日期或二進制類型,最後是字符類型。
2、對於相同級別的數據類型,應該優先選擇佔用空間小的數據類型。
如何選擇正確的整數類型:根據業務整形需要的長度,是否有符號,選擇滿足前面兩者的,儘可能存儲空間小的類型
如何選擇正確的實數類型:
精確運算都用DECIMAL
如何選擇VARCHAR和CHAR類型
VARCHAR類型的存儲特點:
1、用於存儲變長字符串,只佔用必要的存儲空間
2、列的最大長度小於255,則只佔用一個額外字節用於記錄字符串長度,否則用兩個額外字節,(每1長度值一個字符)
長度選擇問題:
1、使用最小的符合需求的長度
2、varchar(5)和varchar(200)存儲 ’mysql‘字符串性能不同(雖然在表中都是6個字節,但是在臨時表中是定長的)
使用場景:
1、字符串列的最大長度比平均長度大很多
2、字符串列很少被更新(經常更新會引起存儲頁的分裂,影響性能)
3、使用了多字節字符集存儲字符串(因爲別的字符集不同類型的字符需要用來表示的字節數都不一樣)
CHAR類型的存儲特點:
1、char類型是定長的
2、字符串存儲在Char類型的列中會刪除末尾的空格
3、char類型的最大寬度爲255
場景:
1、適合存儲長度近似的值(性別,電話,身份證等)
2、使用存儲短字符串
如何存儲日期數據:
DateTime類型
1、以YYYY-MM-DD HH:MM:SS[.fraction]格式存儲日期時間
datetime = YYYY-MM-DD HH:MM:SS
datetime(6) = YYYY-MM-DD HH:MM:SS.fraction
2、該類型與時區無關,不會因爲時區改變而改變,佔用8個字節的存儲空間
3、時間範圍: 1000-01-01 00:00:00 到 9999-12-31 23:59:59
TIMESTAMP類型:
1、存儲了格林尼治時間1970年1月1日到當前時間的秒數,以YYYY-MM-DD HH:MM:SS.[.fraction]顯示
2、佔用4個字節
3、時間範圍: 1970-01-01 到2038-01-19
4、有自動修改功能,默認會自動修改第一列的timestamp,如果沒有插入時沒有指定,會自動填入第一列當前時間,另外一列爲全零
date類型
1、佔用的字節數比字符串、datetime、int少,只要3個字節
2、可以利用時間函數進行日期計算
3、範圍:1000-01-01到9999-12-31之間的日期
time類型: 用於存儲時間數據,格式:HH:MM:SS
注意事項:
1、不要使用字符串來存儲日期,因爲佔用空間大,無法使用時間函數,無法用日期對比
2、使用Int存儲日期不如使用TimeStamp類型。佔用空間小
總結:
物理設計= 存儲空間 + 存儲引擎(沒有特別要求都用innodb) + 數據類型
對於innodb主鍵選擇:
1、主鍵應該儘可能的小
2、應該是順序增長的,可以增加數據的插入效率
3、主鍵和業務主鍵可以不同,如果業務主鍵長,可以設置一個自增的主鍵,然後再設立一個業務主鍵
索引:優化查詢 或者用來order by 排序
索引優化:
索引是由存儲引擎實現的,不同
索引類型:
B-tree索引(用B+樹的結構來存儲數據的)
從根節點
特點:
1、B-tree索引能夠加快數據的查詢速度
2、B-tree索引更適合進行範圍查詢
什麼時候能使用到:
1、匹配範圍查詢
2、精確查詢匹配左前列並範圍匹配另外一列
3、只訪問索引的查詢(覆蓋索引)
4、全值匹配的查詢
5、匹配最左前綴的查詢
6、匹配列前綴查詢(模糊查詢的時候xxx%)
索引優化策略:
索引長度:766 innodb innodb的非主鍵索引後面都會跟有主鍵信息
索引列上不能使用表達式或者函數:(使用了函數就無法利用索引加快速度,通常儘量靈活改寫sql來避免)
前綴索引和索引列的選擇性:
前綴索引是指:當索引列很長的時候使用其前面的一部分作爲索引,
這時候需要考慮索引列的選擇性,必須選擇至選擇性較大的長度才能增加查詢速度,選擇性小的索引,查詢 優化器甚至不會去使用
聯合索引:
如何選擇索引列的順序:
1、經常會被使用到的列優先
2、選擇性高的列優先
3、寬度小的列優先
覆蓋索引:
1、優點:
可以優化緩存,減少磁盤IO操作
可以減少隨機IO,變隨機IO操作爲順序IO操作,計算機執行順序IO會快於隨機IO
可以避免對Innodb主鍵索引的二次查詢,一般是通過索引獲取關鍵字,然後通過關鍵字獲取具體的行數據
可以避免MyISAM表進行系統調用,因爲MyISAM索引存的是數據的地址。
2、無法使用覆蓋索引的情況:
存儲引擎不支持覆蓋索引
查詢中使用了太多的列
使用了雙%好的like查詢(這種情況連索引都無法使用,別說覆蓋索引了)
限制:
1、如果不是按照索引最左列開始查找,則無法使用索引
2、使用索引時不能跳過索引中的列(如 A and B And C 其中AC有索引,B沒有,則C的索引無法使用)
3、Not in 和 < > 操作無法使用索引
4、如果查詢中有某個列的範圍查詢,則其右邊所有列都無法使用索引
索引佔用了大部分數據
用受限制的方式使用索引
哈希索引:
innodb默認會使用的哈希索引,但是是innodb自己根據b+tree索引的使用情況自動去建立的,我們無法自定義創建
特點:
1、基於Hash表實現,只有查詢條件精確匹配Hash索引中的所有列時,才能夠使用到hash索引
2、對於Hash索引中的所有列,存儲引擎都會爲每一行計算一個Hash碼,Hash索引存儲的就是Hash碼無法存儲數據
場景:
1、對於精確查詢比較多的,少範圍查詢的時候
限制:
1、必須兩次查找,先通過哈希,找到索引,然後在找到行數據,只能全鍵值使用
2、無法用於排序
3、只能精確查詢,無法範圍查詢
4、哈希碼的計算,可能有哈希衝突,鍵值重複值大時候,用哈希索引不合適
爲什麼要使用索引:
- 索引大大減少了存儲引擎需要掃描的數據量(索引的大小比較少,每次掃描一頁,大概16K,索引比數據少,因此每頁放的索引是很多的)
- 索引可以幫助我們進行排序以避免使用臨時表
- 索引可以把隨機I/O不變爲順序I/O(索引是順序存儲的,因此Order by的時候也能用到索引)
索引不是越多越好
1、索引會增加寫操作的成本(最好加快寫操作的辦法是刪除所有索引,只留下一個自增的主鍵)
2、太多的索引會增加查詢優化器的選擇時間
使用索引來優化查詢:
1、通過索引掃描來優化排序(對innodb而言,數據邏輯順序和主鍵順序是一樣的)
通過排序操作
按照索引順序掃描數據
要求:
1、索引的列順序和Order By字句的順序完全一致
2、索引中所有列的方向(升序、降序)和Order By字句完全一致
3、Order By 中的字段全部在關聯表中的第一張表中模擬Hash索引(使用tree模擬)
2、模擬Hash索引優化查詢
只能處理鍵值的全值匹配查找
所使用的Hash函數決定着索引鍵的大小
使用一些像md5等函數 使用md5 和 本身進行搜索,這樣使用md5
進行搜索,然後通過 本身進行過濾,來避免衝突 例如:
create index idx_md5 on film(title_md5); (創建索引)
update film set title_md5=md5(title); (使用md5更新列值)
explain select * from film where tile_md5=md5('dog') and title='dog'\G; 查看查詢計劃
3、利用索引優化鎖
索引可以減少鎖定的行數 (innodb使用的是行鎖,通過索引過濾掉大部分行,可以減少行鎖)
索引可以加快處理速度,同時也加快了鎖的釋放(通過索引只需要將很少的行加載入內存中,減少過濾還擊)
索引的維護和優化:
1、刪除重複和冗餘的索引
重複索引:(primary key(id), unique key(id), index(id))這分別爲同一列建立了主鍵索引、唯一索引、單列索引,
主鍵已經是非空的唯一索引,就沒有必要建立唯一索引和同樣的單列索引了。
冗餘索引: (Index(a), index(a,b)) 聯合索引也可以在單獨對單列進行索引(聯合索引可能會很大,有時候需要額外加入一個單獨索引來加速)
重複索引是沒有必要的,冗餘索引有時候是我們刻意爲了優化查詢加上的
通過工具來查看重複的索引,並讓工具給出建議作爲參考:
2、查找未使用過的索引(定時清除整理)
3、更新索引統計信息及減少索引碎片(MySQL優化器會通過查詢索引的統計信息來指定查詢計劃,統計信息不準確的時候會導致優化器做出錯誤的判斷)
analyze table table_name; 重新生成統計信息(成本不一樣:MyISAM的索引都是存儲在磁盤中的,需要多表進行鎖定innodb則是根據我們查詢的情況,把常用的索引存在內存中; 使用語句的時候,可能統計的不全面,估算值,但是速度塊)
optimize table table_name 維護表的碎片(使用不當會導致鎖表)
SQL優化:
獲取有性能問題的SQL方法:
1、通過用戶反饋
2、通過慢查詢日誌
3、實時獲取(服務器壓力突增的時候,等等)
部分語法:
explain select * from rental \G (查看實際執行計劃情況)
創建索引:
create index idx_xxx on table(colum);
update table set title_md5=md5(title);
開啓事務: begin;
回滾:rollback
提交 :commit;
給查詢加入排他鎖:
select * from actor where last_name="WOOD" for update;
MVCC和樂觀鎖區別
https://www.zhihu.com/question/27876575
樂觀鎖和悲觀鎖原理?是什麼?
樂觀鎖實現:
1多版本併發控制+樂觀鎖
2加version字段