Mysql笔记总结
Mysql筆記
1.架構
1.概念
MySQL Server架構自頂向下大致可以分網絡連接層、服務層、存儲引擎層和系統文件層
-
網絡連接層
客戶端連接器(Client Connectors):提供與MySQL服務器建立的支持。
-
服務層
服務層是MySQL Server的核心,主要包含系統管理和控制工具、連接池、SQL接口、解析器、查詢優化器和緩存六個部分。
- 連接池(Connection Pool):負責存儲和管理客戶端與數據庫的連接,一個線程負責管理一個連接。
- 系統管理和控制工具(*Management Services & Utilities):例如備份恢復、安全管理、集群管理等
- SQL接口(SQL Interface):用于接受客戶端發送的各種SQL命令,并且返回用戶需要查詢的結果。比如DML、DDL、存儲過程、視圖、觸發器等。
- 解析器(Parser):負責將請求的SQL解析生成一個"解析樹"。然后根據一些MySQL規則進一步檢查解析樹是否合法。
- 查詢優化器(Optimizer):當“解析樹”通過解析器語法檢查后,將交由優化器將其轉化成執行計劃,然后與存儲引擎交互。
-
存儲引擎層
存儲引擎負責MySQL中數據的存儲與提取,與底層系統文件進行交互。
-
系統文件層
將數據庫的數據和日志存儲在文件系統之上,并完成與存儲引擎的交互,是文件的物理存儲層
- 日志文件
- 配置文件
- 數據文件
- pid 文件
- socket 文件
2.執行流程
通訊機制:
-
全雙工:能同時發送和接收數據,例如平時打電話。
-
半雙工:指的某一時刻,要么發送數據,要么接收數據,不能同時。例如早期對講機
-
單工:只能發送數據或只能接收數據。例如單行道
? 查詢緩存
show variables like '%query_cache%'; show status like '%Qcache%';3.存儲引擎
存儲引擎在MySQL的體系架構中位于第三層,負責MySQL中的數據的存儲和提取,是與文件打交道的子系統,它是根據MySQL提供的文件訪問層抽象接口定制的一種文件訪問機制,這種機制就叫作存儲引擎。
查詢命令
show engines #查詢當前數據庫支持的引擎[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-dR4xfYhm-1599925202767)(D:\拉鉤筆記\lagouNode\4Stage\Mysql(上)]\pic\引擎查詢.png)
-
InnoDB:支持事務,具有提交,回滾和崩潰恢復能力,事務安全
-
MyISAM:不支持事務和外鍵,訪問速度快
-
Memory:利用內存創建表,訪問速度非常快,因為數據在內存,而且默認使用Hash索引,但是一旦關閉,數據就會丟失
1.InnoDB和MyISAM對比
InnoDB和MyISAM是使用MySQL時最常用的兩種引擎類型
-
事務和外鍵
InnoDB支持事務和外鍵,具有安全性和完整性,適合大量insert或update操作
MyISAM不支持事務和外鍵,它提供高速存儲和檢索,適合大量的select查詢操作
-
鎖機制
InnoDB支持行級鎖,鎖定指定記錄。基于索引來加鎖實現
MyISAM支持表級鎖,鎖定整張表
-
索引結構
InnoDB使用聚集索引(聚簇索引),索引和記錄在一起存儲,既緩存索引,也緩存記錄。
MyISAM使用非聚集索引(非聚簇索引),索引和記錄分開
-
并發處理能力
MyISAM使用表鎖,會導致寫操作并發率低,讀之間并不阻塞,讀寫阻塞。
InnoDB讀寫阻塞可以與隔離級別有關,可以采用多版本并發控制(MVCC)來支持高并發
-
存儲文件
InnoDB表對應兩個文件,一個.frm表結構文件,一個.ibd數據文件。InnoDB表最大支持64TB;
MyISAM表對應三個文件,一個.frm表結構文件,一個MYD表數據文件,一個.MYI索引文件。從MySQL5.0開始默認限制是256TB。
2.InnoDB和MyISAM的適用場景
-
MyISAM
-
不需要事務支持(不支持)
-
并發相對較低(鎖定機制問題)
-
數據修改相對較少,以讀為主
-
數據一致性要求不高
-
-
InnoDB
- 需要事務支持(具有較好的事務特性)
- 行級鎖定對高并發有很好的適應能力
- 數據更新較為頻繁的場景
- 數據一致性要求較高
- 硬件設備內存較大,可以利用InnoDB較好的緩存能力來提高內存利用率,減少磁盤IO
3.InnoDB和MyISAM的總結
是否需要事務? 有,InnoDB是否存在并發修改? 有,InnoDB是否追求快速查詢,且數據修改少?是,MyISAM在絕大多數情況下,推薦使用InnoDB4.InnoDB存儲結構
1.內存結構
內存結構主要包括Buffer Pool、Change Buffer、Adaptive Hash Index和Log Buffer四大組件
- Buffer Pool緩存池
- Change Buffer:寫緩沖區,簡稱CB
- Adaptive Hash Index:自適應哈希索引,用于優化對BP數據的查詢。
- Log Buffer:日志緩沖區
Buffer Pool
BP的底層采用鏈表數據結構管理Page。在InnoDB訪問表記錄和索引時會在Page頁中緩存,以后使用可以減少磁盤IO操作,提升效率
Buffer Pool配置參數
show variables like '%innodb_page_size%'; //查看page頁大小 show variables like '%innodb_old%'; //查看lru list中old列表參數 show variables like '%innodb_buffer%'; //查看buffer pool參數 #建議:將innodb_buffer_pool_size設置為總內存大小的60%-80%,innodb_buffer_pool_instances可以設置為多個,這樣可以避免緩存爭奪。Change Buffer
ChangeBuffffer占用BufffferPool空間,默認占25%,最大允許占50%,可以根據讀寫業務量來進行調整。參數innodb_change_buffffer_max_size;
Adaptive Hash Index
自適應哈希索引,用于優化對BP數據的查詢。InnoDB存儲引擎會監控對表索引的查找,如果觀察到建立哈希索引可以帶來速度的提升,則建立哈希索引,所以稱之為自適應。InnoDB存儲引擎會自動根據訪問的頻率和模式來為某些頁建立哈希索引。
Log Buffer
日志緩沖區,用來保存要寫入磁盤上log文件(Redo/Undo)的數據,日志緩沖區的內容定期刷新到磁盤log文件中。日志緩沖區滿時會自動將其刷新到磁盤,當遇到BLOB或多行更新的大事務操作時,增加日志緩沖區可以節省磁盤I/O。
2.磁盤結構
InnoDB磁盤主要包含Tablespaces,InnoDB Data Dictionary,Doublewrite Buffffer、Redo Log和Undo Logs。
Tablespaces
用于存儲表結構和數據。表空間又分為系統表空間、獨立表空間、通用表空間、臨時表空間、Undo表空間等多種類型;
-
系統表空間 默認包含任何用戶在系統表空間創建的表數據和索引數據。系統表空間是一個共享的表空間因為它是被多個表共享的。
-
獨立表空間 默認開啟,獨立表空間是一個單表表空間,該表創建于自己的數據文件中,而非創建于系統表空間中。
-
通用表空間 通用表空間為通過create tablespace語法創建的共享表空間。通用表空間可以創建于mysql數據目錄外的其他表空間,其可以容納多張表,且其支持所有的行格式。
-
撤銷表空間 由一個或多個包含Undo日志文件組成。
-
臨時表空間 mysql服務器正常關閉或異常終止時,臨時表空間將被移除,每次啟動時會被重新創建
InnoDB Data Dictionary
InnoDB數據字典由內部系統表組成,這些表包含用于查找表、索引和表字段等對象的元數據。元數據物理上位于InnoDB系統表空間中。由于歷史原因,數據字典元數據在一定程度上與InnoDB表元數據文件(.frm文件)中存儲的信息重疊。
Doublewrite Buffffer
在BufffferPage的page頁刷新到磁盤真正的位置前,會先將數據存在Doublewrite 緩沖區。
Redo Log
重做日志是一種基于磁盤的數據結構,用于在崩潰恢復期間更正不完整事務寫入的數據。
Undo Logs
撤消日志是在事務開始之前保存的被修改數據的備份,用于例外情況時回滾事務。
5.InnoDB數據文件
1.InnoDB文件存儲結構
InnoDB數據文件存儲結構:分為一個ibd數據文件–>Segment(段)–>Extent(區)–>Page(頁)–>Row(行)
-
Tablesapce 表空間,用于存儲多個ibd數據文件,用于存儲表的記錄和索引。一個文件包含多個段
-
Segment 段,用于管理多個Extent
-
Extent 區,一個區固定包含64個連續的頁,大小為1M。
-
Page 頁,用于存儲多個Row行記錄,大小為16K。
-
Row行,包含了記錄的字段值,事務ID(Trx id)、滾動指針(Roll pointer)、字段指針(Fieldpointers)等信息
通過 information_schema 查看指定表的文件格式
select * from information_schema.innodb_sys_tables;如果某些字段信息過長,無法存儲在B樹節點中,這時候會被單獨分配空間,此時被稱為溢出頁,該字段被稱為頁外列。
REDUNDANT 行格式
使用REDUNDANT行格式,表會將變長列值的前768字節存儲在B樹節點的索引記錄中,其余的存儲在溢出頁上。對于大于等于786字節的固定長度字段InnoDB會轉換為變長字段,以便能夠在頁外存儲。
COMPACT 行格式
與REDUNDANT行格式相比,COMPACT行格式減少了約20%的行存儲空間,但代價是增加了某些操作的CPU使用量。如果系統負載是受緩存命中率和磁盤速度限制,那么COMPACT格式可能更快。如果系統負載受到CPU速度的限制,那么COMPACT格式可能會慢一些。
DYNAMIC 行格式
使用DYNAMIC行格式,InnoDB會將表中長可變長度的列值完全存儲在頁外,而索引記錄只包含指向溢出頁的20字節指針。大于或等于768字節的固定長度字段編碼為可變長度字段。DYNAMIC行格式支持大索引前綴,最多可以為3072字節,可通過innodb_large_prefifix參數控制。
COMPRESSED 行格式
COMPRESSED行格式提供與DYNAMIC行格式相同的存儲特性和功能,但增加了對表和索引數據壓縮的支持。
在創建表和索引時,文件格式都被用于每個InnoDB表數據文件(其名稱與*.ibd匹配)。修改文件格式的方法是重新創建表及其索引,最簡單方法是對要修改的每個表使用以下命令:
ALTER TABLE 表名 ROW_FORMAT=格式類型;6.Undo Log
介紹
Undo:意為撤銷或取消,以撤銷操作為目的,返回指定某個狀態的操作。
Undo Log:數據庫事務開始之前,會將要修改的記錄存放到 Undo 日志里,當事務回滾時或者數據庫崩潰時,可以利用 Undo 日志,撤銷未提交事務對數據庫產生的影響。
Undo Log產生和銷毀:Undo Log在事務開始前產生;事務在提交時,并不會立刻刪除undolog,innodb會將該事務對應的undo log放入到刪除列表中,后面會通過后臺線程purge thread進行回收處理。Undo Log屬于邏輯日志,記錄一個變化過程。例如執行一個delete,undolog會記錄一個insert;執行一個update,undolog會記錄一個相反的update。
show variables like '%innodb_undo%';Undo Log作用
- 實現事務的原子性
- 實現多版本并發控制(MVCC)
事務A手動開啟事務,執行更新操作,首先會把更新命中的數據備份到 Undo Buffffer 中。
事務B手動開啟事務,執行查詢操作,會讀取 Undo 日志數據返回,進行快照讀
7.Redo Log和Binlog
Redo Log介紹
Redo:顧名思義就是重做。以恢復操作為目的,在數據庫發生意外時重現操作。
Redo Log:指事務中修改的任何數據,將最新的數據備份存儲的位置(Redo Log),被稱為重做日志。
Redo Log 的生成和釋放:隨著事務操作的執行,就會生成Redo Log,在事務提交時會將產生
Redo Log寫入Log Buffer,并不是隨著事務的提交就立刻寫入磁盤文件。等事務操作的臟頁寫入到磁盤之后,Redo Log 的使命也就完成了,Redo Log占用的空間就可以重用(被覆蓋寫入)。
show variables like '%innodb_log%';Binlog日志
Redo Log 是屬于InnoDB引擎所特有的日志,而MySQL Server也有自己的日志,即 Binarylog(二進制日志),簡稱Binlog。
Binlog是記錄所有數據庫表結構變更以及表數據修改的二進制日志,不會記錄SELECT和SHOW這類操作。
Binlog兩個最重要的使用場景
- 主從復制:在主庫中開啟Binlog功能,這樣主庫就可以把Binlog傳遞給從庫,從庫拿到Binlog后實現數據恢復達到主從數據一致性。
- 數據恢復:通過mysqlbinlog工具來恢復數據。
Binlog文件操作
Binlog狀態查看
show variables like 'log_bin';開啟Binlog功能
mysql> set global log_bin=mysqllogbin;需要修改my.cnf或my.ini配置文件,在[mysqld]下面增加log_bin=mysql_bin_log,重啟
MySQL服務。
#log-bin=ON #log-bin-basename=mysqlbinlog binlog-format=ROW log-bin=mysqlbinlog使用show binlog events命令
show binary logs; //等價于show master logs; show master status; show binlog events; show binlog events in 'mysqlbinlog.000001';使用mysqlbinlog 命令
mysqlbinlog “文件名”
mysqlbinlog “文件名” > “test.sql”
使用 binlog 恢復數據
//按指定時間恢復 mysqlbinlog --start-datetime="2020-04-25 18:00:00" --stop- datetime="2020-04-26 00:00:00" mysqlbinlog.000002 | mysql -uroot -p1234 //按事件位置號恢復 mysqlbinlog --start-position=154 --stop-position=957 mysqlbinlog.000002 | mysql -uroot -p1234mysqldump:定期全部備份數據庫數據。mysqlbinlog可以做增量備份和恢復操作。
刪除Binlog文件
purge binary logs to 'mysqlbinlog.000001'; //刪除指定文件 purge binary logs before '2020-04-28 00:00:00'; //刪除指定時間之前的文件 reset master; //清除所有文件通過設置expire_logs_days參數來啟動自動清理功能。默認值為0表示沒啟用。設置為1表示超出1天binlog文件會自動刪除掉。
Redo Log和Binlog區別
-
Redo Log是屬于InnoDB引擎功能,Binlog是屬于MySQL Server自帶功能,并且是以二進制文件記錄。
-
Redo Log屬于物理日志,記錄該數據頁更新狀態內容,Binlog是邏輯日志,記錄更新過程。
-
Redo Log日志是循環寫,日志空間大小是固定,Binlog是追加寫入,寫完一個寫下一個,不會覆蓋使用。
-
Redo Log作為服務器異常宕機后事務數據自動恢復使用,Binlog可以作為主從復制和數據恢復使用。Binlog沒有自動crash-safe能力。
2.索引
1.索引類型
索引可以提升查詢速度,會影響where查詢,以及order by排序。MySQL索引類型如下:
-
從索引存儲結構劃分:B Tree索引、Hash索引、FULLTEXT全文索引、R Tree索引
-
從應用層次劃分:普通索引、唯一索引、主鍵索引、復合索引
-
從索引鍵值類型劃分:主鍵索引、輔助索引(二級索引)
-
從數據存儲和索引鍵值邏輯關系劃分:聚集索引(聚簇索引)、非聚集索引(非聚簇索引)
普通索引
基于普通字段建立的索引,沒有任何限制。
-
CREATE INDEX <索引的名字> ON tablename (字段名);
-
ALTER TABLE tablename ADD INDEX [索引的名字] (字段名);
-
CREATE TABLE tablename ( […], INDEX [索引的名字] (字段名) );
唯一索引
索引字段的值必須唯一,但允許有空值 。在創建或修改表時追加唯一約束,就會自動創建對應的唯一索引。
-
CREATE UNIQUE INDEX <索引的名字> ON tablename (字段名);
-
ALTER TABLE tablename ADD UNIQUE INDEX [索引的名字] (字段名);
-
CREATE TABLE tablename ( […], UNIQUE [索引的名字] (字段名) ;
主鍵索引
特殊的唯一索引,不允許有空值。在創建或修改表時追加主鍵約束即可,每個表只能有一個主鍵
-
CREATE TABLE tablename ( […], PRIMARY KEY (字段名) );
-
ALTER TABLE tablename ADD PRIMARY KEY (字段名);
復合索引
單一索引是指索引列為一列的情況,即新建索引的語句只實施在一列上;用戶可以在多個列上建立索引,這種索引叫做組復合索引(組合索引)。復合索引可以代替多個單一索引,相比多個單一索引復合索引所需的開銷更小。
索引同時有兩個概念叫做窄索引和寬索引,窄索引是指索引列為1-2列的索引,寬索引也就是索引列超過2列的索引,設計索引的一個重要原則就是能用窄索引不用寬索引,因為窄索引往往比組合索引更有效
- CREATE INDEX <索引的名字> ON tablename (字段名1,字段名2…);
- ALTER TABLE tablename ADD INDEX [索引的名字] (字段名1,字段名2…);
- CREATE TABLE tablename ( […], INDEX [索引的名字] (字段名1,字段名2…) );
復合索引使用注意事項:
-
何時使用復合索引,要根據where條件建索引,注意不要過多使用索引,過多使用會對更新操作效率有很大影響。
-
如果表已經建立了(col1,col2),就沒有必要再單獨建立(col1);如果現在有(col1)索引,如果查詢需要col1和col2條件,可以建立(col1,col2)復合索引,對于查詢有一定提高。
全文索引
查詢操作在數據量比較少時,可以使用like模糊查詢,但是對于大量的文本數據檢索,效率很低。如果使用全文索引,查詢速度會比like快很多倍。
創建全文索引的方法如下:
-
CREATE FULLTEXT INDEX <索引的名字> ON tablename (字段名);
-
ALTER TABLE tablename ADD FULLTEXT [索引的名字] (字段名);
-
CREATE TABLE tablename ( […], FULLTEXT KEY [索引的名字] (字段名) ;
全文索引使用注意事項
-
全文索引必須在字符串、文本字段上建立。
-
全文索引字段值必須在最小字符和最大字符之間的才會有效。(innodb:3-84;myisam:4-84)
-
全文索引字段值要進行切詞處理,按syntax字符進行切割,例如b+aaa,切分成b和aaa
-
全文索引匹配查詢,默認使用的是等值匹配,例如a匹配a,不會匹配ab,ac。如果想匹配可以在布爾模式下搜索a*
2.索引原理
MySQL官方對索引定義:是存儲引擎用于快速查找記錄的一種數據結構。需要額外開辟空間和數據維護工作。
-
索引是物理數據頁存儲,在數據文件中(InnoDB,ibd文件),利用數據頁(page)存儲。
-
索引可以加快檢索速度,但是同時也會降低增刪改操作速度,索引維護需要代價。
二分查找法
二分查找法也叫作折半查找法,它是在有序數組中查找指定數據的搜索算法。它的優點是等值查詢、范圍查詢性能優秀,缺點是更新數據、新增數據、刪除數據維護成本高。
Hash結構
Hash底層實現是由Hash表來實現的,是根據鍵值 <key,value> 存儲數據的結構。非常適合根據key查找value值,也就是單個key查詢,或者說等值查詢。
InnoDB自適應哈希索引:在使用Hash索引訪問時,一次性查找就能定位數據,等值查詢效率要優于B+Tree。
自適應哈希索引的建立使得InnoDB存儲引擎能自動根據索引頁訪問的頻率和模式自動地為某些熱點頁建立哈希索引來加速訪問。
show engine innodb status \G; show variables like '%innodb_adaptive%';B+Tree結構
MySQL數據庫索引采用的是B+Tree結構,在B-Tree結構上做了優化改造。
聚簇索引和輔助索引
聚簇索引和非聚簇索引:B+Tree的葉子節點存放主鍵索引值和行記錄就屬于聚簇索引;如果索引值和行記錄分開存放就屬于非聚簇索引。
主鍵索引和輔助索引:B+Tree的葉子節點存放的是主鍵字段值就屬于主鍵索引;如果存放的是非主鍵值就屬于輔助索引(二級索引)。
在InnoDB引擎中,主鍵索引采用的就是聚簇索引結構存儲。
- 聚簇索引(聚集索引)
聚簇索引是一種數據存儲方式,InnoDB的聚簇索引就是按照主鍵順序構建 B+Tree結構。B+Tree的葉子節點就是行記錄,行記錄和主鍵值緊湊地存儲在一起。 這也意味著 InnoDB 的主鍵索引就是數據表本身,它按主鍵順序存放了整張表的數據,占用的空間就是整個表數據量的大小。通常說的主鍵索引就是聚集索引
- 輔助索引
InnoDB輔助索引,也叫作二級索引,是根據索引列構建 B+Tree結構。但在 B+Tree 的葉子節點中只存了索引列和主鍵的信息。二級索引占用的空間會比聚簇索引小很多, 通常創建輔助索引就是為了提升查詢效率。一個表InnoDB只能創建一個聚簇索引,但可以創建多個輔助索引。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-IiZRHApa-1599925202779)(D:\拉鉤筆記\lagouNode\4Stage\Mysql(上)]\pic\聚簇索引.png)
- 非聚簇索引
與InnoDB表存儲不同,MyISAM數據表的索引文件和數據文件是分開的,被稱為非聚簇索引結構。
3.索引分析與優化
MySQL 提供了一個 EXPLAIN 命令,它可以對 SELECT 語句進行分析,并輸出 SELECT 執行的詳細信息,供開發人員有針對性的優化。
EXPLAIN SELECT * from user WHERE id < 3;- select_type
表示查詢的類型。常用的值如下:
-
SIMPLE : 表示查詢語句不包含子查詢或union
-
PRIMARY:表示此查詢是最外層的查詢
-
UNION:表示此查詢是UNION的第二個或后續的查詢
-
EXPLAIN SELECT * from user WHERE id < 3;DEPENDENT UNION:UNION中的第二個或后續的查詢語句,使用了外面查詢結果
-
UNION RESULT:UNION的結果
-
SUBQUERY:SELECT子查詢語句
-
DEPENDENT SUBQUERY:SELECT子查詢語句依賴外層查詢的結果。
最常見的查詢類型是SIMPLE,表示我們的查詢沒有子查詢也沒用到UNION查詢。
- type
表示存儲引擎查詢數據時采用的方式。比較重要的一個屬性,通過它可以判斷出查詢是全表掃描還是基于索引的部分掃描。常用屬性值如下,
從上至下效率依次增強。
ALL:表示全表掃描,性能最差。
index:表示基于索引的全表掃描,先掃描索引再掃描全表數據。
range:表示使用索引范圍查詢。使用>、>=、<、<=、in等等。
ref:表示使用非唯一索引進行單值查詢。
eq_ref:一般情況下出現在多表join查詢,表示前面表的每一個記錄,都只能匹配后面表的一行結果。
const:表示使用主鍵或唯一索引做等值查詢,常量查詢。
NULL:表示不用訪問表,速度最快。
- possible_keys
表示查詢時能夠使用到的索引。注意并不一定會真正使用,顯示的是索引名稱
- key
表示查詢時真正使用到的索引,顯示的是索引名稱
- rows
MySQL查詢優化器會根據統計信息,估算SQL要查詢到結果需要掃描多少行記錄。原則上rows是越少效率越高,可以直觀的了解到SQL效率高低。
- Extra
Extra表示很多額外的信息,各種操作會在Extra提示相關信息,常見幾種如下:
Using where
表示查詢需要通過索引回表查詢數據。
Using index
表示查詢需要通過索引,索引就可以滿足所需數據。
Using filesort
表示查詢出來的結果需要額外排序,數據量小在內存,大的話在磁盤,因此有Using fifilesort建議優化。
Using temprorary
查詢使用到了臨時表,一般出現于去重、分組等操作。
4.回表查詢
通過索引查詢主鍵值,然后再去聚簇索引查詢記錄信息
5.覆蓋索引
只需要在一棵索引樹上就能獲取SQL所需的所有列數據,無需回表,速度更快,這就叫做索引覆蓋。
實現索引覆蓋最常見的方法就是:將被查詢的字段,建立到組合索引。
6.最左前綴原則
復合索引使用時遵循最左前綴原則,最左前綴顧名思義,就是最左優先,即查詢中使用到最左邊的列,那么查詢就會使用到索引,如果從索引的第二列開始查找,索引將失效。
7.面試題
1.LIKE查詢
面試題:MySQL在使用like模糊查詢時,索引能不能起作用?
回答:MySQL在使用Like模糊查詢時,索引是可以被使用的,只有把%字符寫在后面才會使用到索引。
select * from user where name like ‘%o%’; //不起作用
select * from user where name like ‘o%’; //起作用
select * from user where name like ‘%o’; //不起作用
2.NULL查詢
面試題:如果MySQL表的某一列含有NULL值,那么包含該列的索引是否有效?
對MySQL來說,NULL是一個特殊的值,從概念上講,NULL意味著“一個未知值”,它的處理方式與其他值有些不同。比如:不能使用=,<,>這樣的運算符,對NULL做算術運算的結果都是NULL,count時不會包括NULL行等,NULL比空字符串需要更多的存儲空間等。
雖然MySQL可以在含有NULL的列上使用索引,但NULL和其他數據還是有區別的,不建議列上允許為NULL。最好設置NOT NULL,并給一個默認值,比如0和 ‘’ 空字符串等,如果是datetime類型,也可以設置系統當前時間或某個固定的特殊值,例如’1970-01-01 00:00:00’。
8.索引與排序
MySQL查詢支持filesort和index兩種方式的排序。
filesort是先把結果查出,然后在緩存或磁盤進行排序操作,效率較低。
index是指利用索引自動實現排序,不需另做排序操作,效率會比較高。
如果我們Explain分析SQL,結果中Extra屬性顯示Using filesort,表示使用了filesort排序方式,需要優化。
如果Extra屬性顯示Using index時,表示覆蓋索引,也表示所有操作在索引上完成,也可以使用index排序方式,建議大家盡可能采用覆蓋索引。
Sql會使用index方式的排序
-
ORDER BY 子句索引列組合滿足索引最左前列
explain select id from user order by id; //對應(id)、(id,name)索引有效 -
WHERE子句+ORDER BY子句索引列組合滿足索引最左前列
explain select id from user where age=18 order by name; //對應 (age,name)索引
Sql會使用fifilesort方式的排序
- 對索引列同時使用了ASC和DESC
- WHERE子句和ORDER BY子句滿足最左前綴,但where子句使用了范圍查詢(例如>、<、in等)
- ORDER BY或者WHERE+ORDER BY索引列沒有滿足索引最左前列
- 使用了不同的索引,MySQL每次只采用一個索引,ORDER BY涉及了兩個索引
- WHERE子句與ORDER BY子句,使用了不同的索引
- WHERE子句或者ORDER BY子句中索引列使用了表達式,包括函數表達式
9.查詢優化
慢查詢定位
查看 MySQL 數據庫是否開啟了慢查詢日志和慢查詢日志文件的存儲位置的命令如下:
SHOW VARIABLES LIKE 'slow_query_log%'通過如下命令開啟慢查詢日志:
SET global slow_query_log = ON; SET global slow_query_log_file = 'OAK-slow.log'; SET global log_queries_not_using_indexes = ON; SET long_query_time = 10;-
long_query_time:指定慢查詢的閥值,單位秒。如果SQL執行時間超過閥值,就屬于慢查詢記錄到日志文件中。
-
log_queries_not_using_indexes:表示會記錄沒有使用索引的查詢SQL。前提是slow_query_log的值為ON,否則不會奏效。
查看慢查詢日志
-
文本方式查看
-
使用mysqldumpslow查看
慢查詢優化
-
索引和慢查詢
- 如何判斷是否為慢查詢?
MySQL判斷一條語句是否為慢查詢語句,主要依據SQL語句的執行時間,它把當前語句的執行時間跟 long_query_time 參數做比較
- 如何判斷是否應用了索引?
通過 explain命令分析查看,檢查結果中的 key 值,是否為NULL。
- 應用了索引是否一定快?
select * from user where id>0; 從主鍵索引的最左邊的葉節點開始向右掃描整個索引樹,進行了全表掃描,此時索引就失去了意義。
select * from user where id = 2 ; 使用了索引的快速搜索功能,并且有效地減少了掃描行數。
-
提高索引過濾性
案例:
表:student 字段:id,name,sex,age 造數據:insert into student (name,sex,age) select name,sex,age from student; SQL 案例:select * from student where age=18 and name like '張%';(全表掃 描)優化一:
alter table student add index(name); //追加name索引優化二:
alter table student add index(age,name); //追加age,name索引優化三:
index condition pushdown 優化的效果還是很不錯的。再進一步優化,我們可以把名 字的第一個字和年齡做一個聯合索引,這里可以使用 MySQL 5.7 引入的虛擬列來實現。//為user表添加first_name虛擬列,以及聯合索引(first_name,age) alter table student add first_name varchar(2) generated always as (left(name, 1)), add index(first_name, age); explain select * from student where first_name='張' and age=18; -
慢查詢原因總結
- 全表掃描:explain分析type屬性all
- 全索引掃描:explain分析type屬性index
- 索引過濾性不好:靠索引字段選型、數據量和狀態、表設計
- 頻繁的回表查詢開銷:盡量少用select *,使用覆蓋索引
分頁查詢優化
- 一般性分頁
第一個參數指定第一個返回記錄行的偏移量,注意從0開始;
第二個參數指定返回記錄行的最大數目;
如果只給定一個參數,它表示返回最大的記錄行數目;
思考1:如果偏移量固定,返回記錄量對執行時間有什么影響?
select * from user limit 10000,1; select * from user limit 10000,10; select * from user limit 10000,100; select * from user limit 10000,1000; select * from user limit 10000,10000;結果:在查詢記錄時,返回記錄量低于100條,查詢時間基本沒有變化,差距不大。隨著查詢記錄量越大,所花費的時間也會越來越多。
思考2:如果查詢偏移量變化,返回記錄數固定對執行時間有什么影響?
select * from user limit 1,100; select * from user limit 10,100; select * from user limit 100,100; select * from user limit 1000,100; select * from user limit 10000,100;結果:在查詢記錄時,如果查詢記錄量相同,偏移量超過100后就開始隨著偏移量增大,查詢時間急劇的增加。(這種分頁查詢機制,每次都會從數據庫第一條記錄開始掃描,越往后查詢越慢,而且查詢的數據越多,也會拖慢總查詢速度。)
分頁優化方案
第一步:利用覆蓋索引優化
select * from user limit 10000,100; select id from user limit 10000,100;第二步:利用子查詢優化
select * from user limit 10000,100; select * from user where id>= (select id from user limit 10000,1) limit 100;原因:使用了id做主鍵比較(id>=),并且子查詢使用了覆蓋索引進行優化。
3.MySQL事務和鎖
ACID 特性
一個邏輯工作單元要成為事務,必須滿足這 4 個特性,即所謂的 ACID:
原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)和持久性(Durability)
原子性
原子性:事務是一個原子操作單元,其對數據的修改,要么全都執行,要么全都不執行。
持久性
持久性:指的是一個事務一旦提交,它對數據庫中數據的改變就應該是永久性的,后續的操作或故障不應該對其有任何影響,不會丟失。
隔離性
隔離性:指的是一個事務的執行不能被其他事務干擾,即一個事務內部的操作及使用的數據對其他的并發事務是隔離的
一致性
事務開始之前和事務結束之后,數據庫的完整性限制未被破壞。一致性包括兩方面的內容,分別是約束一致性和數據一致性。
一致性也可以理解為數據的完整性。數據的完整性是通過原子性、隔離性、持久性來保證的,而這3個特性又是通過 Redo/Undo 來保證的。
事務控制的演進
并發事務
事務并發處理可能會帶來一些問題,比如:更新丟失、臟讀、不可重復讀、幻讀等。
-
更新丟失
當兩個或多個事務更新同一行記錄,會產生更新丟失現象。可以分為回滾覆蓋和提交覆蓋。
回滾覆蓋:一個事務回滾操作,把其他事務已提交的數據給覆蓋了。
提交覆蓋:一個事務提交操作,把其他事務已提交的數據給覆蓋了。
-
臟讀
一個事務讀取到了另一個事務修改但未提交的數據。
-
不可重復讀
一個事務中多次讀取同一行記錄不一致,后面讀取的跟前面讀取的不一致。
-
幻讀
一個事務中多次按相同條件查詢,結果不一致。后續查詢的結果和面前查詢結果不同,多了或少了幾行記錄。
排隊
完全順序執行所有事務的數據庫操作,不需要加鎖,簡單的說就是全局排隊。序列化執行所有的事務單元,數據庫某個時刻只處理一個事務操作,特點是強一致性,處理性能低。
排他鎖
引入鎖之后就可以支持并發處理事務,如果事務之間涉及到相同的數據項時,會使用排他鎖,或叫互斥鎖,先進入的事務獨占數據項以后,其他事務被阻塞,等待前面的事務釋放鎖。
讀寫鎖
讀和寫操作:讀讀、寫寫、讀寫、寫讀。
讀寫鎖就是進一步細化鎖的顆粒度,區分讀操作和寫操作,讓讀和讀之間不加鎖,這樣下面的兩個事務就可以同時被執行了
MVCC
多版本控制MVCC,也就是Copy on Write的思想。MVCC除了支持讀和讀并行,還支持讀和寫、寫和讀的并行,但為了保證一致性,寫和寫是無法并行的。
概念
MVCC(Multi Version Concurrency Control)被稱為多版本控制,是指在數據庫中為了實現高并發的數據訪問,對數據進行多版本處理,并通過事務的可見性來保證事務能看到自己應該看到的數據版本。
MVCC實現原理
MVCC最大的好處是讀不加鎖,讀寫不沖突。在讀多寫少的系統應用中,讀寫不沖突是非常重要的,極大的提升系統的并發性能,這也是為什么現階段幾乎所有的關系型數據庫都支持 MVCC 的原因,不過目前MVCC只在 Read Commited 和 Repeatable Read 兩種隔離級別下工作。
MVCC只在 Read Commited 和 Repeatable Read 兩種隔離級別下工作。
在 MVCC 并發控制中,讀操作可以分為兩類: 快照讀(Snapshot Read)與當前讀 (Current Read)。
-
快照讀:讀取的是記錄的快照版本(有可能是歷史版本),不用加鎖。(select)
-
當前讀:讀取的是記錄的最新版本,并且當前讀返回的記錄,都會加鎖,保證其他事務不會再并發修改這條記錄。(select… for update 或lock in share mode,insert/delete/update)
事務隔離級別
隔離級別類型
- 讀未提交
Read Uncommitted 讀未提交:解決了回滾覆蓋類型的更新丟失,但可能發生臟讀現象,也就是可能讀取到其他會話中未提交事務修改的數據。
- 已提交讀
Read Committed 讀已提交:只能讀取到其他會話中已經提交的數據,解決了臟讀。但可能發生不可重復讀現象,也就是可能在一個事務中兩次查詢結果不一致。
- 可重復度
Repeatable Read 可重復讀:解決了不可重復讀,它確保同一事務的多個實例在并發讀取數據時,會看到同樣的數據行。不過理論上會出現幻讀,簡單的說幻讀指的的當用戶讀取某一范圍的數據行時,另一個事務又在該范圍插入了新行,當用戶在讀取該范圍的數據時會發現有新的幻影行。
- 可串行化
Serializable 串行化:所有的增刪改查串行執行。它通過強制事務排序,解決相互沖突,從而解決幻度的問題。這個級別可能導致大量的超時現象的和鎖競爭,效率低下
事務隔離級別和鎖的關系
-
事務隔離級別是SQL92定制的標準,相當于事務并發控制的整體解決方案,本質上是對鎖和MVCC使用的封裝,隱藏了底層細節。
-
鎖是數據庫實現并發控制的基礎,事務隔離性是采用鎖來實現,對相應操作加不同的鎖,就可以防止其他事務同時對數據進行讀寫操作。
-
對用戶來講,首先選擇使用隔離級別,當選用的隔離級別不能解決并發問題或需求時,才有必要在開發中手動的設置鎖。
MySQL默認隔離級別:可重復讀
Oracle、SQLServer默認隔離級別:讀已提交
一般使用時,建議采用默認隔離級別,然后存在的一些并發問題,可以通過悲觀鎖、樂觀鎖等實現處理
MySQL隔離級別控制
查看MySQL當前數據庫的事務隔離級別命令
show variables like 'tx_isolation'; select @@tx_isolation;設置隔離級別
set tx_isolation='READ-UNCOMMITTED'; set tx_isolation='READ-COMMITTED'; set tx_isolation='REPEATABLE-READ'; set tx_isolation='SERIALIZABLE';鎖機制和實戰
鎖分類
-
從操作的粒度可分為表級鎖、行級鎖和頁級鎖。
- 表級鎖:每次操作鎖住整張表。鎖定粒度大,發生鎖沖突的概率最高,并發度最低。應用在MyISAM、InnoDB、BDB 等存儲引擎中。
- 行級鎖:每次操作鎖住一行數據。鎖定粒度最小,發生鎖沖突的概率最低,并發度最高。應用在InnoDB 存儲引擎中。
- 頁級鎖:每次鎖定相鄰的一組記錄,鎖定粒度界于表鎖和行鎖之間,開銷和加鎖時間界于表鎖和行鎖之間,并發度一般。應用在BDB 存儲引擎中。
-
從操作的類型可分為讀鎖和寫鎖。
-
讀鎖(S鎖):共享鎖,針對同一份數據,多個讀操作可以同時進行而不會互相影響。
-
寫鎖(X鎖):排他鎖,當前寫操作沒有完成前,它會阻斷其他寫鎖和讀鎖。
IS鎖、IX鎖:意向讀鎖、意向寫鎖,屬于表級鎖,S和X主要針對行級鎖。在對表記錄添加S或X鎖之前,會先對表添加IS或IX鎖。
S鎖:事務A對記錄添加了S鎖,可以對記錄進行讀操作,不能做修改,其他事務可以對該記錄追加。
S鎖,但是不能追加X鎖,需要追加X鎖,需要等記錄的S鎖全部釋放。
X鎖:事務A對記錄添加了X鎖,可以對記錄進行讀和修改操作,其他事務不能對記錄做讀和修改操作
-
-
從操作的性能可分為樂觀鎖和悲觀鎖。
- 樂觀鎖:一般的實現方式是對記錄數據版本進行比對,在數據更新提交的時候才會進行沖突檢測,如果發現沖突了,則提示錯誤信息。
- 悲觀鎖:在對一條數據修改的時候,為了避免同時被其他人修改,在修改數據之前先鎖定,再修改的控制方式。共享鎖和排他鎖是悲觀鎖的不同實現,但都屬于悲觀鎖范疇。
行鎖原理
在InnoDB引擎中,我們可以使用行鎖和表鎖,其中行鎖又分為共享鎖和排他鎖。InnoDB行鎖是通過對索引數據頁上的記錄加鎖實現的,
主要實現算法有 3 種:Record Lock、Gap Lock 和 Next-key Lock。
- RecordLock鎖:鎖定單個行記錄的鎖。(記錄鎖,RC、RR隔離級別都支持)
- GapLock鎖:間隙鎖,鎖定索引記錄間隙,確保索引記錄的間隙不變。(范圍鎖,RR隔離級別支持)
- Next-key Lock 鎖:記錄鎖和間隙鎖組合,同時鎖住數據,并且鎖住數據前后范圍。(記錄鎖+范圍鎖,RR隔離級別支持)
在RR隔離級別,InnoDB對于記錄加鎖行為都是先采用Next-Key Lock,但是當SQL操作含有唯一索引時,Innodb會對Next-Key Lock進行優化,降級為RecordLock,僅鎖住索引本身而非范圍。
-
select … from 語句:InnoDB引擎采用MVCC機制實現非阻塞讀,所以對于普通的select語句,InnoDB不加鎖
-
select … from lock in share mode語句:追加了共享鎖,InnoDB會使用Next-Key Lock鎖進行處理,如果掃描發現唯一索引,可以降級為RecordLock鎖。
-
select … from for update語句:追加了排他鎖,InnoDB會使用Next-Key Lock鎖進行處理,如果掃描發現唯一索引,可以降級為RecordLock鎖。
-
update … where 語句:InnoDB會使用Next-Key Lock鎖進行處理,如果掃描發現唯一索引,可以降級為RecordLock鎖。
-
delete … where 語句:InnoDB會使用Next-Key Lock鎖進行處理,如果掃描發現唯一索引,可以降級為RecordLock鎖。
-
insert語句:InnoDB會在將要插入的那一行設置一個排他的RecordLock鎖
悲觀鎖
悲觀鎖(Pessimistic Locking),是指在數據處理過程,將數據處于鎖定狀態,一般使用數據庫的鎖機制實現。從廣義上來講,前面提到的行鎖、表鎖、讀鎖、寫鎖、共享鎖、排他鎖等,這些都屬于悲觀鎖范疇。
- 表級鎖
表級鎖每次操作都鎖住整張表,并發度最低。
常用命令如下:手動增加表鎖
lock table 表名稱 read|write,表名稱2 read|write;查看表上加過的鎖
show open tables;刪除表鎖
unlock tables;表級讀鎖會阻塞寫操作,但是不會阻塞讀操作。而寫鎖則會把讀和寫操作都阻塞。
- 共享鎖
共享鎖又稱為讀鎖,簡稱S鎖。共享鎖就是多個事務對于同一數據可以共享一把鎖,都能訪問到數據,但是只能讀不能修改。使用共享鎖的方法是在select … lock in share mode,只適用查詢語句。
總結:事務使用了共享鎖(讀鎖),只能讀取,不能修改,修改操作被阻塞。
- 排他鎖(行級鎖-寫鎖)
排他鎖又稱為寫鎖,簡稱X鎖。排他鎖就是不能與其他鎖并存,如一個事務獲取了一個數據行的排他鎖,其他事務就不能對該行記錄做其他操作,也不能獲取該行的鎖。
使用排他鎖的方法是在SQL末尾加上for update,innodb引擎默認會在update,delete語句加上for update。行級鎖的實現其實是依靠其對應的索引,所以如果操作沒用到索引的查詢,那么會鎖住全表記錄。
總結:事務使用了排他鎖(寫鎖),當前事務可以讀取和修改,其他事務不能修改,也不能獲取記錄鎖(select… for update)。如果查詢沒有使用到索引,將會鎖住整個表記錄
樂觀鎖
在數據庫操作時,想法很樂觀,認為這次的操作不會導致沖突,因此在數據庫操作時并不做任何的特殊處理,即不加鎖,而是在進行事務提交時再去判斷是否有沖突了。
悲觀鎖和樂觀鎖都可以解決事務寫寫并發,在應用中可以根據并發處理能力選擇區分,比如對并發率要求高的選擇樂觀鎖;對于并發率要求低的可以選擇悲觀鎖。
樂觀鎖實現原理
- 使用版本字段(version)
先給數據表增加一個版本(version) 字段,每操作一次,將那條記錄的版本號加 1。version是用來查看被讀的記錄有無變化,作用是防止記錄在業務處理期間被其他事務修改。
- 使用時間戳(Timestamp)
與使用version版本字段相似,同樣需要給在數據表增加一個字段,字段類型使用timestamp時間戳。也是在更新提交的時候檢查當前數據庫中數據的時間戳和自己更新前取到的時間戳進行對比,如果一致則提交更新,否則就是版本沖突,取消操作。
樂觀鎖案例
第一步:查詢商品信息
select (quantity,version) from products where id=1;第二部:根據商品信息生成訂單
insert into orders ... insert into items ...第三部:修改商品庫存
update products set quantity=quantity-1,version=version+1 where id=1 and version=#{version};死鎖與解決方案
- 表鎖死鎖
用戶A訪問表A(鎖住了表A),然后又訪問表B;另一個用戶B訪問表B(鎖住了表B),然后企圖訪問表A.
解決方案:
這種死鎖比較常見,是由于程序的BUG產生的,除了調整的程序的邏輯沒有其它的辦法。仔細分析程序的邏輯,對于數據庫的多表操作時,盡量按照相同的順序進行處理,盡量避免同時鎖定兩個資源,如操作A和B兩張表時,總是按先A后B的順序處理, 必須同時鎖定兩個資源時,要保證在任何時刻都應該按照相同的順序來鎖定資源。
- 行級鎖死鎖
如果在事務中執行了一條沒有索引條件的查詢,引發全表掃描,把行級鎖上升為全表記錄鎖定(等價于表級鎖),多個這樣的事務執行后,就很容易產生死鎖和阻塞,最終應用系統會越來越慢,發生阻塞或死鎖。
解決方案:
解決一:
SQL語句中不要使用太復雜的關聯多表的查詢;使用explain“執行計劃"對SQL語句進行分析,對于有全表掃描和全表鎖定的SQL語句,建立相應的索引進行優化。
解決二:
-
在同一個事務中,盡可能做到一次鎖定所需要的所有資源
-
按照id對資源排序,然后按順序進行處理
==================================
- 共享鎖轉換為排他鎖
事務A 查詢一條紀錄,然后更新該條紀錄;此時事務B 也更新該條紀錄,這時事務B 的排他鎖由于事務A 有共享鎖,必須等A 釋放共享鎖后才可以獲取,只能排隊等待。事務A 再執行更新操作時,此處發生死鎖,因為事務A 需要排他鎖來做更新操作。但是,無法授予該鎖請求,因為事務B 已經有一個排他鎖請求,并且正在等待事務A 釋放其共享鎖。
事務A: select * from dept where deptno=1 lock in share mode; //共享鎖,1 update dept set dname='java' where deptno=1;//排他鎖,3 事務B: update dept set dname='Java' where deptno=1;//由于1有共享鎖,沒法獲取排他鎖,需等待,2解決方案:
-
對于按鈕等控件,點擊立刻失效,不讓用戶重復點擊,避免引發同時對同一條記錄多次操作;
-
使用樂觀鎖進行控制。樂觀鎖機制避免了長事務中的數據庫加鎖開銷,大大提升了大并發量下的系統性能。需要注意的是,由于樂觀鎖機制是在我們的系統中實現,來自外部系統的用戶更新操作不受我們系統的控制,因此可能會造成臟數據被更新到數據庫中;
死鎖排查:
- 查看死鎖日志
通過show engine innodb status\G命令查看近期死鎖日志信息。
使用方法:1、查看近期死鎖日志信息;2、使用explain查看下SQL執行計劃
- 查看鎖狀態變量
通過**show status like’innodb_row_lock%‘**命令檢查狀態變量,分析系統中的行鎖的爭奪情況
Innodb_row_lock_current_waits:當前正在等待鎖的數量
Innodb_row_lock_time:從系統啟動到現在鎖定總時間長度
Innodb_row_lock_time_avg: 每次等待鎖的平均時間
Innodb_row_lock_time_max:從系統啟動到現在等待最長的一次鎖的時間
Innodb_row_lock_waits:系統啟動后到現在總共等待的次數
如果等待次數高,而且每次等待時間長,需要分析系統中為什么會有如此多的等待,然后著手定制優化。
mysql集群架構
概念
實現高可用的方案有以下幾種架構模式:
- 主從模式
簡單靈活,能滿足多種需求。比較主流的用法,但是寫操作高可用需要自行處理。
- 雙主模式
互為主從,有雙主雙寫、雙主單寫兩種方式,建議使用雙主單寫
centos虛擬機安裝mysql
cd /usr/local/src tar -xvf mysql-5.7.28-1.el7.x86_64.rpm-bundle.tar## centos自帶 mariadb,查詢并刪除 rpm -qa|grep mariadb rpm -e mariadb-libs-5.5.41-2.el7_0.x86_64 --nodeps## i表示安裝,v表示顯示安裝過程,h表示顯示進度 ## 安裝common包 rpm -ivh mysql-community-common-5.7.28-1.el7.x86_64.rpm ## 安裝lib包 rpm -ivh mysql-community-libs-5.7.28-1.el7.x86_64.rpm ## 安裝libs-compat包 rpm -ivh mysql-community-libs-compat-5.7.28-1.el7.x86_64.rpm ## 安裝client包 rpm -ivh mysql-community-client-5.7.28-1.el7.x86_64.rpm ## 安裝server包 rpm -ivh mysql-community-server-5.7.28-1.el7.x86_64.rpm ## 安裝devel包 rpm -ivh mysql-community-devel-5.7.28-1.el7.x86_64.rpm ## 初始化mysql mysqld --initialize --user=mysql ## 查詢密碼 cat /var/log/mysqld.log ## 獲取臨時密碼 ZTl%tXzk#57 ## 開機自啟 systemctl start mysqld.service ## 查詢狀態是否啟動 systemctl status mysqld.service ##登錄mysql mysql -uroot -p## 進入mysql 設置 密碼 set password=password('root'); ## mysql授權外部鏈接 GRANT REPLICATION SLAVE ON *.* TO 'root'@'%' identified by 'root'; GRANT all privileges ON *.* TO 'root'@'%' identified by 'root'; ##刷新 flush privileges; ## 退出 關閉防火墻 exit#mysql內執行 systemctl stop iptables; systemctl stop firewalld; ## 禁用防火墻 systemctl disable firewalld.servicemysql主從復制
MySQL主從模式是指數據可以從一個MySQL數據庫服務器主節點復制到一個或多個從節點。MySQL 默認采用異步復制方式,這樣從節點不用一直訪問主服務器來更新自己的數據,從節點可以復制主數據庫中的所有數據庫,或者特定的數據庫,或者特定的表。
mysql主從復制用途:
-
實時災備,用于故障切換(高可用)
-
讀寫分離,提供查詢服務(讀擴展)
-
數據備份,避免影響業務(高可用)
主從復制整體分為以下三個步驟:
-
主庫將數據庫的變更操作記錄到Binlog日志文件中
-
從庫讀取主庫中的Binlog日志文件信息寫入到從庫的Relay Log中繼日志中
-
從庫讀取中繼日志信息在從庫中進行Replay,更新從庫數據信息
搭建流程
主服務器master
從服務器 slave
主服務器
-
從庫服務器能連通主庫
-
主庫開啟binlog日志(設置log-bin參數)
-
主從server-id不同
進入mysql的命令行
GRANT REPLICATION SLAVE ON *.* TO 'root'@'%' identified by 'root'; GRANT all privileges ON *.* TO 'root'@'%' identified by 'root'; //刷新 flush privileges;從服務器
問題
mysql主從復制存在的問題:
-
主庫宕機后,數據可能丟失
-
從庫只有一個SQL Thread,主庫寫壓力大,復制很可能延時
解決方法:
-
半同步復制—解決數據丟失的問題
-
并行復制----解決從庫復制延遲的問題
半同步復制
semi-sync意思是MASTER只需要接收到其中一臺SLAVE的返回信息,就會commit;否則需等待直至切換成異步再提交
主庫安裝semi
進入mysql 安裝配置semi
##是否支持動態加載 select @@have_dynamic_loading; ##開啟插件 show plugins; ##安裝semi install plugin rpl_semi_sync_master soname 'semisync_master.so'; ##查看 show variables like '%semi%'; //============下面部分無視 ##開啟semi set global rpl_semi_sync_master_enabled=1; ##1000毫秒 set global rpl_semi_sync_master_timeout=1000;從庫安裝semi
進入mysql 安裝配置semi
##安裝semi install plugin rpl_semi_sync_slave soname 'semisync_slave.so'; ##查看 show variables like '%semi%'; ##開啟semi set global rpl_semi_sync_master_enabled=1; ## 重啟 stop slave; start slave;全同步復制
為了兼容MySQL 5.6基于庫的并行復制,5.7引入了新的變量slave-parallel-type,其可以配置的值有:
DATABASE(默認值,基于庫的并行復制方式)、LOGICAL_CLOCK(基于組提交的并行復制方式)。
show variables like '%binlog_group%'; ## 先關閉 stop slave; ## 提交的時間 set global binlog_group_commit_sync_delay=1000; ## 提交的組數量 set global binlog_group_commit_sync_no_delay_count=100;show variables like '%slave%'; ## 并行組提交方式 set global slave_parallel_type=LOGICAL_CLOCK; ## 線程數 set global slave_parallel_workers=8;show variables like '%relay_log%'; ## 轉發的日志回復 set global relay_log_recovery=1; ## 存儲方式 set relay_log_info_repository='table';直接寫配置文件與set global的區別
set global后重啟服務,配置屬性消失
寫到my.ini文件中,不會消失
配置etc下的my.ini文件
relay_log_recovery=1 slave_parallel_type=LOGICAL_CLOCK slave_parallel_workers=8 relay_log_info_repository=table; master_info_repository=table;#重啟 systemctl restart mysqld # 查詢 show variables like '%relay_log%';并行復制配置與調優
- binlog_transaction_dependency_history_size 用于控制集合變量的大小
- binlog_transaction_depandency_tracking 控制binlog文件中事務之間的依賴關系
- transaction_write_set_extraction 用于控制事務的檢測算法
- master_info_repository 性能提升
- slave_parallel_workers SQL線程
- slave_preserve_commit_order 實現更小粒度的并行復制
讀寫分離
mysql-proxy
解壓 mysql-proxy-0.8.5-linux-el6-x86-64bit.tar.gz文件
創建配置文件
vim /etc/mysql-proxy.cnf user=rootadmin-username=rootadmin-password=root#代理的主機IP名 proxy-address=192.168.95.134:4040 #指定主庫的ip proxy-backend-address=192.168.95.130:3306 #指定讀庫(從庫)的ip proxy-read-only-backend-addresses=192.168.95.132:3306,192.168.95.133:3306 #采用lua腳本管理 proxy-lua-script=/share/doc/mysql-proxy/rw-spiltting.lua #log路徑 log-file=/var/log/mysql-proxy.log log-level=debug #進程的運行模式 daemon=true #是否重啟 keepalive=true修改權限
chmod 660 /etc/mysql-proxy.cnf修改rw-spilttind.lua腳本
#連接池 #最小鏈接 4改成1 min_idle_connections = 1 min_idle_connections = 8啟動mysql-proxy
./mysql-proxy --defaults-file=/etc/mysql-proxy.cnf雙主復制
配置master1
進入master1的etc/my.cnf
#開啟binlog日期 log_bin=mysql-bin server-id=1 ## 同步日志 sync-binlog=1 ## 忽略一些庫 binlog-ignore-db=performance_schema binlog-ignore-db=informance_schema binlog-ignore-db=sys ## 同步一些表 binlog-do-db=xxx(表名) ## relay_log功能 relay_log=mysql-relay-bin ##從服務日志更新 log_slave_updates=1 ##1.3.5.7.9 ##指定自動遞增 auto_increment_offset=1 ##增量 auto_increment_increment=2重啟mysql
systemctl restart mysqld進入mysql,查詢,指定授權(授權過,直接取消)
show master status ## 授權 GRANT REPLICATION SLAVE ON *.* TO 'root'@'%' identified by 'root'; GRANT all privileges ON *.* TO 'root'@'%' identified by 'root'; ##刷新 flush privileges;配置master2
進入master2的etc/my.cnf
#開啟binlog日期 log_bin=mysql-bin server-id=3 ## 同步日志 sync-binlog=1 ## 忽略一些庫 binlog-ignore-db=performance_schema binlog-ignore-db=informance_schema binlog-ignore-db=sys## relay_log功能 relay_log=mysql-relay-bin ##從服務日志更新 log_slave_updates=1 ##2,4,6,8,10 ##指定自動遞增 auto_increment_offset=2 ##增量 auto_increment_increment=2重啟mysql
systemctl restart mysqld授權
## 授權 GRANT REPLICATION SLAVE ON *.* TO 'root'@'%' identified by 'root'; GRANT all privileges ON *.* TO 'root'@'%' identified by 'root'; ## 刷新 flush privileges;查詢狀態
show master status指定復制操作
master1指定master2(fileID,Position)
change master to master_host='59.151.15.36',master_port='3306',master_user='root',master_password='root',master_log_file=' mysql-bin.000016 ',master_log_pos=107;## 啟動slave start slave; ## 查詢狀態 show slave status\Gmaster2指定master1(fileID,Position)
change master to master_host='59.151.15.36',master_port='3306',master_user='root',master_password='root',master_log_file=' mysql-bin.000016 ',master_log_pos=107;## 啟動slave start slave; ## 查詢狀態 show slave status\GMMM架構
MMM(Master-Master Replication Manager for MySQL)是一套用來管理和監控雙主復制,支持雙主故障切換 的第三方軟件。
MMM 包含writer和reader兩類角色,分別對應寫節點和讀節點。
-
當 writer節點出現故障,程序會自動移除該節點上的VIP
-
寫操作切換到 Master2,并將Master2設置為writer將所有Slave節點會指向Master2
MHA架構
MHA(Master High Availability)是一套比較成熟的 MySQL 高可用方案,也是一款優秀的故障切換和主從提升的高可用軟件。
MHA由兩部分組成:MHA Manager(管理節點)和MHA Node(數據節點)。
-
MHA Manager可以單獨部署在一臺獨立的機器上管理多個master-slave集群,也可以部署在一臺slave節點上。負責檢測master是否宕機、控制故障轉移、檢查MySQL復制狀況等。
-
MHA Node運行在每臺MySQL服務器上,不管是Master角色,還是Slave角色,都稱為Node,是被監控管理的對象節點,負責保存和復制master的二進制日志、識別差異的中繼日志事件并將其差異的事件應用于其他的slave、清除中繼日志。
MHA故障處理機制:
-
把宕機master的binlog保存下來
-
根據binlog位置點找到最新的slave
-
用最新slave的relay log修復其它slave
-
將保存下來的binlog在最新的slave上恢復
-
將最新的slave提升為master
-
將其它slave重新指向新提升的master,并開啟主從復制
MHA優點:
-
自動故障轉移快
-
主庫崩潰不存在數據一致性問題
-
性能優秀,支持半同步復制和異步復制
-
一個Manager監控節點可以監控多個集群
主備切換策略
主備切換是指將備庫變為主庫,主庫變為備庫,有可靠性優先和可用性優先兩種策略。
主備延遲問題
主備延遲是由主從數據同步延遲導致的,與數據同步有關的時間點主要包括以下三個:
-
主庫 A 執行完成一個事務,寫入 binlog,我們把這個時刻記為 T1;
-
之后將binlog傳給備庫 B,我們把備庫 B 接收完 binlog 的時刻記為 T2;
-
備庫 B 執行完成這個binlog復制,我們把這個時刻記為 T3。
分庫分表
使用分庫分表時,主要有垂直拆分和水平拆分兩種拆分模式,都屬于物理空間的拆分。
垂直拆分:由于表數量多導致的單個庫大。將表拆分到多個庫中。
水平拆分:由于表記錄多導致的單個庫大。將表記錄拆分到多個表中。
垂直拆分
垂直拆分是將表按庫進行分離,或者修改表結構按照訪問的差異將某些列拆分出去。
- 垂直分庫
- 垂直分表
一個表中字段過多,還有有些字段經常使用,有些字段不經常使用,或者還有text等字段信息。
垂直拆分優點:
-
拆分后業務清晰,拆分規則明確;
-
易于數據的維護和擴展;
-
可以使得行數據變小,一個數據塊 (Block) 就能存放更多的數據,在查詢時就會減少 I/O 次數;
-
可以達到最大化利用 Cache 的目的,具體在垂直拆分的時候可以將不常變的字段放一起,將經常改變的放一起;
-
便于實現冷熱分離的數據表設計模式。
垂直拆分缺點:
-
主鍵出現冗余,需要管理冗余列;
-
會引起表連接 JOIN 操作,可以通過在業務服務器上進行 join 來減少數據庫壓力,提高了系統的復雜度;
-
依然存在單表數據量過大的問題;
-
事務處理復雜。
水平拆分
水平拆分又稱為橫向拆分。 相對于垂直拆分,它不再將數據根據業務邏輯分類,而是通過某個字段(或某幾個字段),根據某種規則將數據分散至多個庫或表中,每個表僅包含數據的一部分。
下圖所示
區分
水平拆分:解決表中記錄過多問題。
垂直拆分:解決表過多或者是表字段過多問題
水平拆分重點考慮拆分規則:例如范圍、時間或Hash算法等。
水平拆分優點:
-
拆分規則設計好,join 操作基本可以數據庫做;
-
不存在單庫大數據,高并發的性能瓶頸;
-
切分的表的結構相同,應用層改造較少,只需要增加路由規則即可;
-
提高了系統的穩定性和負載能力。
水平拆分缺點:
-
拆分規則難以抽象;
-
跨庫Join性能較差;
-
分片事務的一致性難以解決;
-
數據擴容的難度和維護量極大。
-
日常工作中,我們通常會同時使用兩種拆分方式,垂直拆分更偏向于產品/業務/功能拆分的過程,在技術上我們更關注水平拆分的方案。
主鍵策略
- UUID
UUID是通用唯一識別碼(Universally Unique Identififier)的縮寫。
UUID在生成時使用到了以太網卡地址、納秒級時間、芯片ID碼和隨機數等信息,目的是讓分布式系統中的所有元素都能有唯一的識別信息
使用UUID做主鍵,可以在本地生成,沒有網絡消耗,所以生成性能高。但是UUID比較長,沒有規律性,耗費存儲空間。
- SNOWFLAKE(雪花ID)
SnowFlake是Twitter開源的分布式ID生成算法,結果是一個long型的ID,long型是8個字節,64-bit。其核心思想是:使用41bit作為毫秒數,10bit作為機器的ID(5個bit是數據中心,5個bit的機器ID),12bit作為毫秒內的流水號,最后還有一個符號位,永遠是0。
分片策略
將一個數據庫打碎成多個的過程就叫做分片,分片是屬于橫向擴展方案。
數據庫擴展方案:
-
橫向擴展:一個庫變多個庫,加機器數量
-
縱向擴展:一個庫還是一個庫,優化機器性能,加高配CPU或內存
-
基于范圍分片
根據特定字段的范圍進行拆分,比如用戶ID、訂單時間、產品價格等。例如:
{[1 - 100] => Cluster A, [101 - 199] => Cluster B}
優點:新的數據可以落在新的存儲節點上,如果集群擴容,數據無需遷移。
缺點:數據熱點分布不均,數據冷熱不均勻,導致節點負荷不均。
- 哈希取模分片
假設有n臺設備,編號為0 ~ n-1,通過Hash(Key) % n就可以確定數據所在的設備編號。該模式也稱為離散分片
- 一致性哈希分片
一致性Hash是將數據按照特征值映射到一個首尾相接的Hash環上,同時也將節點(按照IP地址或者機器名Hash)映射到這個環上。對于數據,從數據在環上的位置開始,順時針找到的第一個節點即為數據的存儲節點。
擴容方案
當系統用戶進入了高速增長期時,即便是對數據進行分庫分表,但數據庫的容量,還有表的數據量也總會達到天花板。當現有數據庫達到承受極限時,就需要增加新服務器節點數量進行橫向擴容。
- 停機擴容
優點:簡單
缺點:
? 停止服務,缺乏高可用
? 程序員壓力山大,需要在指定時間完成
? 如果有問題沒有及時測試出來啟動了服務,運行后發現問題,數據會丟失一部分,難以回滾。
適用場景:
? 小型網站
? 大部分游戲
? 對高可用要求不高的服務
- 平滑擴容
平滑擴容就是將數據庫數量擴容成原來的2倍,比如:由2個數據庫擴容到4個數據庫
平滑擴容方案能夠實現n庫擴2n庫的平滑擴容,增加數據庫服務能力,降低單庫一半的數據量。其核心
原理是:成倍擴容,避免數據遷移。
優點:
? 擴容期間,服務正常進行,保證高可用
? 相對停機擴容,時間長,項目組壓力沒那么大,出錯率低
? 擴容期間遇到問題,隨時解決,不怕影響線上服務
? 可以將每個數據庫數據量減少一半
缺點:
? 程序復雜、配置雙主同步、雙主雙寫、檢測數據同步等
? 后期數據庫擴容,比如成千上萬,代價比較高
適用場景:
? 大型網站
? 對高可用要求高的服務
問題
1.虛擬機centos7執行ip addr命令看不到ip地址?
方案一:
#切換到root用戶 su root #編輯修改文件 vi /etc/sysconfig/network-scripts/ifcfg-eno16777736 ONBOOT=no #修改成ONBOOT=yes #強制保存 :wq! #重啟網絡服務 service netword restart方案二:
https://blog.csdn.net/weixin_43343006/article/details/100094624?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param
https://blog.csdn.net/liunian0714/article/details/78560473
2.上傳文件:permission is not allowed?
#切換到root用戶 su root #給目錄賦權限 chmod 777 src3.克隆虛擬機黑屏無法啟動
在克隆完虛擬機以后,啟動之前,再虛擬機屬性->適配器-.從新生成maca地址
在首選項中,把虛擬機打印 打開
(主要解決方式)https://blog.csdn.net/wpw2000/article/details/108121096
https://blog.csdn.net/Jarbein/article/details/91851350
https://blog.csdn.net/fengy_jav/article/details/104458930
4.虛擬機克隆修改網關IP
cd /etc/sysconfig/network-scripts/ ##生成UUid uuidgen單詞
Parser 解析
Optimizer 查詢優化器
Engines 引擎
Pluggable Storage Engines 存儲引擎層
partition 分割,隔斷
dependent 依賴
identical 相同的
Pessimistic 悲觀的
relay 轉發
dynamic 動態的
parallel 并行,平行
recovery 恢復,回復
trace 追蹤,發現
問題:虛擬機centos7執行ip addr命令看不到ip地址
fg-eno16777736
ONBOOT=no #修改成ONBOOT=yes
#強制保存
:wq!
#重啟網絡服務
service netword restart
3.克隆虛擬機黑屏無法啟動
在克隆完虛擬機以后,啟動之前,再虛擬機屬性->適配器-.從新生成maca地址
在首選項中,把虛擬機打印 打開
(主要解決方式)https://blog.csdn.net/wpw2000/article/details/108121096
https://blog.csdn.net/Jarbein/article/details/91851350
https://blog.csdn.net/fengy_jav/article/details/104458930
4.虛擬機克隆修改網關IP
cd /etc/sysconfig/network-scripts/ ##生成UUid uuidgenhttps://blog.csdn.net/qq_35461394/article/details/92788603?utm_medium=distribute.pc_relevant.none-task-blog-title-6&spm=1001.2101.3001.4242
https://blog.csdn.net/weixin_30426065/article/details/102344340?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param
https://blog.csdn.net/qq_39192827/article/details/85952823
待測試
https://blog.csdn.net/woSHIxiaobai2/article/details/104222073?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param
https://www.cnblogs.com/Guugle/p/12982803.html
單詞
Parser 解析
Optimizer 查詢優化器
Engines 引擎
Pluggable Storage Engines 存儲引擎層
partition 分割,隔斷
dependent 依賴
identical 相同的
Pessimistic 悲觀的
relay 轉發
dynamic 動態的
parallel 并行,平行
recovery 恢復,回復
trace 追蹤,發現
問題:虛擬機centos7執行ip addr命令看不到ip地址
總結
- 上一篇: java Poi导入exel表格的数据,
- 下一篇: Mysql半双工主从复制