MySQL面試寶典

==============================================
# 參數
==============================================
autocommit
事務操做中是否自動提交,若是爲1則自動提交,爲0則須要commit。

back_log
mysql服務在很短的時間內有不少的鏈接請求時該參數就會發揮做用。 若是短期內有很大鏈接數可考慮增長該值。不過限制於系統層面的鏈接數。 5.6.6以前默認50, 5.6.6以後基於50+(max_connections/5)公式,上限900

binlog_format
binlog的記錄格式。

connect_timeout
這個超時使用在MySQL服務器和客戶端交換受權包時。默認10秒。

key_buffer_size
只用於MyISAM存儲引擎表,緩存MyISAM存儲。

sort_buffer_size
主要用於SQL語句在內存中的臨時排序

join_buffer_size
錶鏈接時使用。

log_bin
打開或關閉binlog的參數。須要指定server-id。

innodb_buffer_pool_size
InnoDB緩存表和索引數據的內存區域。

innodb_fast_shutdown
innodb關閉的幾種模式。動態參數,默認值爲1,可選值爲0,1,2
爲0時,所有髒葉刷盤而且change buffer合併。關閉緩慢。
爲1時,跳過以上操做。關閉迅速。
爲2時,innodb只會刷新他的log,當mysql崩潰的時候,提交的事務不會丟失。可是恢復的時間會很長。
通常來講,使用innodb_fast_shutdown在緊急狀況下或者troubleshooting中。好比數據有在內存中有雪崩的危險。

sync_binlog
sync_binlog 的默認值是0,像操做系統刷其餘文件的機制同樣,MySQL不會同步到磁盤中去而是依賴操做系統來刷新binary log。
當sync_binlog =N (N>0) ,MySQL 在每寫 N次 二進制日誌binary log時,會使用fdatasync()函數將它的寫二進制日誌binary log同步到磁盤中去。

innodb_flush_log_at_trx_commit
0:log buffer將每秒一次地寫入log file中,而且log file的flush(刷到磁盤)操做同時進行。該模式下在事務提交的時候,不會主動觸發寫入磁盤的操做。
1:每次事務提交時MySQL都會把log buffer的數據寫入log file,而且flush(刷到磁盤)中去,該模式爲系統默認。
2:每次事務提交時mysql都會把log buffer的數據寫入log file,可是flush(刷到磁盤)操做並不會同時進行。該模式下,MySQL會每秒執行一次 flush(刷到磁盤)操做。

innodb_log_file_size
設置每一個log file的大小,默認48M。太小日誌輪轉(rotate)受影響,影響checkpoint,過大恢復緩慢。設置多大是一門技術,優化是一個調優的過程。

innodb_thread_concurrency
innodb可限制併發線程數。默認值爲0,表示不受限制。若是參數設置大於0,則表示檢查機制開啓,容許進入的線程數就是參數的值。若是設置過大會由於增長消耗系統層面的鏈接和資源致使性能退化。 通常狀況下,值得設定應小於CPU的核數。 根據系統的負載,硬件環境調整參數。

innodb_flush_method
有三個值:fdatasync(默認),O_DSYNC,O_DIRECT
默認是fdatasync,只要MYSQL線程進行了刷新動做,那麼他的這些文件的數據必定會同步到磁盤
爲O_DSYNC時,不繞過pape cache, 每次write的數據不只會在page cache裏寫入,還會寫入存儲設備,而且,O_SYNC保證每次write返回後,數據都已經寫入page cache和存儲設備。
爲O_DIRECT時,該文件的讀寫操做將會繞過page cache,直接與存儲設備打交道
建議設置爲O_DIREC 避免雙緩衝(double buffering)和下降swap的壓力

max_connections
容許最大併發的鏈接數。若是由於max_connections而致使的鏈接錯誤,會致使狀態參數Connection_errors_max_connections的增長。

max_user_connection
每一個數據庫用戶的最大鏈接

max_error_count
show warnings語句最多能顯示的error,warnings。

wait_timeout
MySQL客戶端的數據庫鏈接閒置最大時間值。

thread_concurrency
應設爲CPU核數的2倍

innodb_additional_mem_pool_size
設置了InnoDB存儲引擎用來存放數據字典信息以及一些內部數據結構的內存空間大小,因此當咱們一個MySQL Instance中的數據庫對象很是多的時候,是須要適當調整該參數的大小以確保全部數據都能存放在內存中提升訪問效率的。

innodb_log_buffer_size
InnoDB存儲引擎的事務日誌所使用的緩衝區。

==============================================
# MySQL 規範
==============================================
必須使用InnoDB存儲引擎
必須使用UTF8字符集
數據表、數據字段必須加入中文註釋
禁止使用存儲過程、視圖、觸發器、Event(解讀:高併發大數據的互聯網業務,架構設計思路是「解放數據庫CPU,將計算轉移到服務層」,併發量大的狀況下,這些功能極可能將數據庫拖死,業務邏輯放到服務層具有更好的擴展性,可以輕易實現「增機器就加性能」。數據庫擅長存儲與索引,CPU計算仍是讓給應用服務器去作吧。)
禁止存儲大文件或者大照片(解讀:爲什麼要讓數據庫作它不擅長的事情?大文件和照片存儲在文件系統,數據庫裏存URI多好)
只容許使用內網域名,而不是ip鏈接數據庫
表必須有主鍵,例如自增主鍵
必須把字段定義爲NOT NULL而且提供默認值(null的列使索引/索引統計/值比較都更加複雜,對MySQL來講更難優化、null 這種類型MySQL內部須要進行特殊處理,增長數據庫處理記錄的複雜性;同等條件下,表中有較多空字段的時候,數據庫的處理性能會下降不少、)
禁止使用TEXT、BLOB類型(會浪費更多的磁盤和內存空間,非必要的大量的大字段查詢會淘汰掉熱數據,致使內存命中率急劇下降,影響數據庫性能)
禁止在更新十分頻繁、區分度不高的屬性上創建索引
禁止使用INSERT INTO t_xxx VALUES(xxx),必須顯示指定插入的列屬性
禁止在WHERE條件的屬性上使用函數或者表達式(SELECT uid FROM t_user WHERE from_unixtime(day)>='2017-02-15' 會致使全表掃描,正確的寫法是:SELECT uid FROM t_user WHERE day>= unix_timestamp('2017-02-15 00:00:00'))

==============================================
# MySQL新特性
==============================================
MySQL 5.5
1.InnoDB做爲默認的數據庫存儲引擎。
2.用兩個新的參數取代了 innodb_file_io_threads,那就是innodb_read_io_threads 和 innodb_write_io_threads,你就能夠根據你的 CPU 核數來更改。
3.在 MySQL5.1.X 版本,因爲代碼寫死,最多隻會刷新 100 個髒頁到磁盤,合併 20 個插入緩衝,即便磁盤有能力處理更多的請求,也只會處理這麼多,這樣在更新量較大(好比大批量 INSERT)的時候,髒頁刷新可能會跟不上,致使性能降低。而在 MySQL5.5.X 版本里,innodb_io_capacity 參數能夠動態調整刷新髒頁的數量,在必定程度上解決了這一問題。
4.INNODB 同時支持多個 BufferPool 實例,經過 innodb_buffer_pool_instances 參數來增長InnoDB_Buffer_Pool 實例的個數。
5.增長了半同步複製,relay-log的自我修復,增長了 relay_log_recovery 參數,這個參數的做用是:當 slave 從庫宕機後,假如 Relay-Log 損壞了,致使一部分中繼日誌沒有處理,則自動放棄全部未執行的 relay-log,而且從新從 MASTER 上獲取日誌,這樣保證 relay-log 的完整。默認狀況下該功能是關閉的,將 relay_log_recovery 的值設置爲 1 時,可在 slave 從庫上開啓該功能,建議開啓。

MySQL 5.6
1.全文索引的支持。
2. undo log可獨立出系統表空間,原來存在ibd系統表空間裏。(innodb_undo_directory、innodb_undo_tablespaces)
3.支持多線程複製。slave_parallel_workers
4.支持延遲複製。CHANGE master TO MASTER_DELAY=600;
5.新增GTID複製。
6.ICP優化(Index Condition Pushdown):index_condition_pushdown=on。ICP的優化用於range, ref, eq_ref, and ref_or_null訪問方法
Index Condition Pushdown (ICP)是MySQL用索引去表裏取數據的一種優化。禁用ICP(MySQL5.6以前),引擎層會利用索引在基表中尋找數據行,而後返回給MySQL Server層,再去爲這些數據行進行WHERE後的條件的過濾(回表)。啓用ICP(MySQL5.6以後),若是部分WHERE條件能使用索引中的字段,MySQL會把這部分下推到引擎層。存儲引擎經過使用索引把知足的行從表中讀取出。ICP減小了引擎層訪問基表的次數和MySQL Server 訪問存儲引擎的次數。總之是 ICP的優化在引擎層就可以過濾掉大量的數據,減小io次數,提升查詢語句性能。
7.支持read-only事務。

MySQL 5.7
1.動態修改 Buffer Pool。
2.MySQL默認的部署策略發生了變化,變得更加安全。mysql_install_db 棄用了,改用 mysqld。
3.支持JSON數據類型
4.已經刪除了test數據庫,默認安裝完後是沒有test數據庫。
5.能夠爲用戶設置密碼過時策略。
6.能夠」鎖」住用戶,用以暫時禁用某個用戶。
7.generated column,這一列由其餘列計算而得。
8.sys schema。
9.在線開啓GTID。
10.MySQL 5.7版本已經支持」真正」的並行複製功能。


MySQL 8.0
1.MySQL 8.0 的速度要比 MySQL 5.7 快 2 倍。
2.提供 NoSQL 存儲功能。
3.新增了一個叫窗口函數的概念,它能夠用來實現若干新的查詢方式。窗口函數與 SUM()、COUNT() 這種集合函數相似,但它不會將多行查詢結果合併爲一行,而是將結果放回多行當中。即窗口函數不須要 GROUP BY。
4.隱藏索引。
5.降序索引。
6.utf8mb4 做爲 MySQL 的默認字符集。
7.取消默認MyISAM系統表。
8.取消Query Cache。

==============================================
# InnoDB
==============================================
InnoDB體系結構
內存:
innodb_buffer_pool由包含數據、索引、insert buffer ,adaptive hash index,lock 信息及數據字典。
redo log buffer用來緩存重作日誌。
additional memory pool:用來緩存LRU鏈表、等待、鎖等數據結構。

線程
master thread負責刷新緩存數據到磁盤並協調調度其它後臺進程。
IO thread 分爲 insert buffer、log、read、write進程。分別用來處理insert buffer、重作日誌、讀寫請求的IO回調。
purge thread用來回收undo 頁
page cleaner thread用來刷新髒頁。

關鍵特性之 insert buffer:
專門爲維護非惟一輔助索引的更新設計的。由於innodb的記錄是按主鍵的順序存放的,因此主鍵的插入是順序的,而彙集索引對應的輔助索引的更新則是離散的,爲了不大量離散讀寫,先檢查要更新的索引頁是否已經緩存在了內存中,若是沒有,先將輔助索引的更新都放入緩衝(inset buffer區),等待合適機會(master thread的定時操做,索引塊須要被讀取時,insert buffer bitmap檢測到對應的索引頁不夠用時)進行insert buffer和索引頁的合併。由於輔助索引緩存到insert buffer中時並不會讀取磁盤上的索引頁,以致於沒法校驗索引的惟一性,因此不適用惟一輔助索引。innodb中全部的非惟一輔助索引的insert buffer均由同一棵二叉樹維護。二叉樹的非葉子節點由space(表空間id)+marker(兼容老版本的insert buffer)+offset(在表空間中的位置)構成,葉子節點由space+marker+offset+metadata(進入順序+類型+標誌)+輔助索引構成,進行merge合併時,按順序進行回放。mysql5.1以後,insert buffer支持change_buffer,還能夠緩衝非惟一輔助索引的update\delete操做。insert buffer的二叉樹結構是存放在共享表空間中的,因此經過獨立表空間恢復表時,執行check table操做會失敗,由於輔助索引的數據可能還在insert buffer中,須要經過repair table 重建表上所有的輔助索引。爲了保證每次 merge insert buffer成功,表空間中每隔256個連續區就有一個insert buffer bitmap頁用來記錄索引頁的可用空間。insert buffer bitmap頁老是處於這個連續區間的第二頁,每一個索引頁在insert buffer bitmap中佔4 bit。能夠經過show engine innodb stauts\G;查看insert buffer and adaptive hash index 查看insert buffer的合併數量、空閒頁數量、自己的大小、合併次數及索引操做次數。經過索引操做次數與合併次數的的比例能夠判斷出insert buffer所帶來的性能提高。

關鍵特性之 double write:
由於髒頁刷新到磁盤的寫入單元小於單個頁的大小,若是在寫入過程當中數據庫忽然宕機,可能會使數據頁的寫入不完成,形成數據頁的損壞。而redo log中記錄的是對頁的物理操做,若是數據頁損壞了,經過redo log也沒法進行恢復。因此爲了保證數據頁的寫入安全,引入了double write。double write的實現分兩個部分,一個是緩衝池中2M的內存塊大小,一個是共享表空間中連續的128個頁,大小是2M。髒頁從flush list刷新時,並非直接刷新到磁盤而是先調用函數(memcpy),將髒頁拷貝到double write buffer中,而後再分兩次,每次1M將double write buffer 刷新到磁盤double write 區,以後再調用fsync操做,同步到磁盤。若是應用在業務高峯期,innodb_dblwr_pages_written:innodb_dblwr_writes遠小於64:1,則說明,系統寫入壓力不大。雖然,double write buffer刷新到磁盤的時候是順序寫,但仍是是有性能損耗的。若是系統自己支持頁的安全性保障(部分寫失效防範機制),如ZFS,那麼就能夠禁用掉該特性(skip_innodb_doublewrite)。

關鍵特性之 adaptive hash index:
innodb會對錶上的索引頁的查詢進行監控,若是發現創建hash索引可以帶來性能提高,就自動建立hash索引。hash索引的建立是有條件的,首先是一定可以帶來性能提高。其次數據庫以特定模式的連續訪問超過了100次,經過該模式被訪問的頁的訪問次數超過了1/16的記錄行數。自適應hash根據B+樹中的索引構造而來,只需爲這個表的熱點頁構造hash索引而不是爲整張表都構建。一樣能夠經過show engine innodb status\G中的 insert buffer and adaptive hash index(hash searches/s non-hash searches)查看hash index的使用狀況。

MyISAM 和 InnoDB 的區別
1. InnoDB支持事務,MyISAM不支持,對於InnoDB每一條SQL語言都默認封裝成事務,自動提交,這樣會影響速度,因此最好把多條SQL語言放在begin和commit之間,組成一個事務;
2. InnoDB支持外鍵,而MyISAM不支持。對一個包含外鍵的InnoDB錶轉爲MYISAM會失敗;
3. InnoDB支持行級鎖,而MyISAM只支持表級鎖;
4. InnoDB是彙集索引,數據文件是和索引綁在一塊兒的,必需要有主鍵,經過主鍵索引效率很高。可是輔助索引須要兩次查詢,先查詢到主鍵,而後再經過主鍵查詢到數據。所以,主鍵不該該過大,由於主鍵太大,其餘索引也都會很大。而MyISAM是非彙集索引,數據文件是分離的,索引保存的是數據文件的指針。主鍵索引和輔助索引是獨立的。
5. InnoDB不保存表的具體行數,執行select count(*) from table時須要全表掃描。而MyISAM用一個變量保存了整個表的行數,執行上述語句時只須要讀出該變量便可,速度很快;
6. Innodb不支持全文索引,而MyISAM支持全文索引,查詢效率上MyISAM要高;
7. InnoDB 把數據和索引存放在一個數據文件裏面,而MyISAM 表被存放在三個文件 frm:存放表格定義。 MYD:數據文件。MYI:索引文件。

爲何InnoDB表最好要有自增列作主鍵?
1.InnoDB引擎表是基於B+樹的索引組織表
2.使用自增列(INT/BIGINT類型)作主鍵,這時候寫入順序是自增的,和B+數葉子節點分裂順序一致;

關於query cache
Query Cache(查詢緩存,如下簡稱QC)存儲SELECT語句及其產生的數據結果,特別適用於:頻繁提交同一個語句,而且該表數據變化不是很頻繁的場景,例如一些靜態頁面,或者頁面中的某塊不常常發生變化的信息。QC有可能會從InnoDB Buffer Pool或者MyISAM key buffer裏讀取結果。
因爲QC須要緩存最新數據結果,所以表數據發生任何變化(INSERT、UPDATE、DELETE或其餘可能產生數據變化的操做),都會致使QC被刷新。
QC嚴格要求2次SQL請求要徹底同樣,包括SQL語句,鏈接的數據庫、協議版本、字符集等因素都會影響。
關閉QC: query_cache_size = 0, query_cache_type = 0
==============================================
# 複製
==============================================
複製原理:
1. 主:binlog線程——記錄下全部改變了數據庫數據的語句,放進master上的binlog中;
2. 從:io線程——在使用start slave 以後,負責從master上拉取 binlog 內容,放進 本身的relay log中;
3. 從:sql執行線程——執行relay log中的語句;

MySQL複製格式小結
基於語句級的複製
binlog=statement

優勢:
(1)binlog文件較小。
(2)日誌是包含用戶執行的原始SQL,方便統計和審計。
(3)出現最先可binlog、兼容較好。
(4)binlog方便閱讀,方便故障修復。

缺點:
存在安全隱患,可能致使主從不一致。
對一些系統函數不能準確複製或是不能複製:load file()、uuid()、user()、found rows()、sysdate()。

基於行級的複製
binlog=row
優勢:
(1)相比statement更加安全的複製格式。
(2)在某些狀況下複製速度更快(SQL複雜、表有主鍵)。
(3)系統的特殊函數也能夠複製。
(4)更少的鎖。

缺點:
(1)binary log比較大(MySQL 5.6 支持binlog row image)。
(2)單語句更新/刪除的表執行過多,會造成大量binlog。
(3)沒法從binlog看見用戶執行的SQL(MySQL5.6增長一個新的Event binlog_rw_query_log_event記錄用戶的query)。

基於混合級複製
1.混個使用ROW和statement格式,對於DDL記錄會stement,對於TABLE裏的行操做記錄爲ROW格式。
2.若是使用innodb表,事務級別使用了read commeitted or read uncommitted 日誌級別只能使用row格式。
3.單在使用row格式中DDL語句仍是會記錄成statement格式。
4.mixed格式,那麼在如下幾種狀況會自動將binlog的模式由SBR模式改爲RBR。
5.當DML語句更新一個NDB表時。
6.當函數中包含UUID()時。
7.2個及以上包含AUTO_INCREMENT字段的表被更新時。
8.行任何INSERT DELAYED語句時。
9.用UDF時。
10.視圖中必需要求使用RBR時,例如建立視圖是使用了UUID()函數。

異步複製
異步複製,主庫將事務 Binlog 事件寫入到 Binlog 文件中,此時主庫只會通知一下 Dump 線程發送這些新的 Binlog,而後主庫就會繼續處理提交操做,而此時不會保證這些 Binlog 傳到任何一個從庫節點上。

全同步複製
全同步複製,當主庫提交事務以後,全部的從庫節點必須收到、APPLY而且提交這些事務,而後主庫線程才能繼續作後續操做。但缺點是,主庫完成一個事務的時間會被拉長,性能下降。

半同步複製
半同步複製,是介於全同步複製與全異步複製之間的一種,主庫只須要等待至少一個從庫節點收到而且 Flush Binlog 到 Relay Log 文件便可,主庫不須要等待全部從庫給主庫反饋。同時,這裏只是一個收到的反饋,而不是已經徹底完成而且提交的反饋,如此,節省了不少時間

主從複製延時判斷
當遇到從庫延遲時,要怎麼作?
首先輸入 show slave status \G;看一下。

在生產環境中,主從複製經常會有複製延遲的現象,主要是master是併發的寫,而slave是單線程的應用relay log,因此會出現複製延時,在MySQL 5.6版本中有了基於庫的多線程複製。還有MariaDB的並行複製。可是咱們使用MySQL 5.5的版本也比較多。如何判斷複製是否延時呢?工具如今可使用的有pt-heartbeat,可是若是咱們本身明白怎麼樣判斷複製是否延時的話,本身寫簡單的shell腳本或者python腳本也能夠完成。

複製是否延時的判斷標準以下:
Master_Log_File: restoredb-bin.000013
Read_Master_Log_Pos: 2421074
Relay_Log_File: restoredb2-relay-bin.000010
Relay_Log_Pos: 2419771
Relay_Master_Log_File: restoredb-bin.000013
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 2421074
Relay_Log_Space: 2420428
不要經過Seconds_Behind_Master去判斷,該值表示slave上SQL線程和IO線程之間的延遲
判斷方法以下:
一、首先看 Relay_Master_Log_File 和 Master_Log_File 是否有差別
二、若是Relay_Master_Log_File 和 Master_Log_File 有差別的話,那說明延遲很大
三、若是Relay_Master_Log_File 和 Master_Log_File 沒有差別,再來看Exec_Master_Log_Pos 和 Read_Master_Log_Pos 的差別,那麼更加嚴謹的作法是同時在主庫執行show master status和在從庫上面執行show slave status 的輸出進行比較。MHA就是這樣保證數據一致性的。MMM都沒有作到。這也算MHA比MMM更加優秀的地方。


GTID的限制
1.不支持非事務引擎(從庫報錯,stop slave;start slave;忽略)。
2.不支持create table ... select 語句複製(主庫直接報錯)。
3.不容許一個SQL同時更新一個事務引擎和非事務引擎的表。
4.在一個複製組中,必需要求統一開啓GTID或者是關閉GTID。
5.開啓GTID須要重啓。
6.開啓GTID後,就再也不使用原來的傳統的複製方式。
7.對於create temporary table和drop temporary語句不支持。
8.不支持sql_slave_skip_counter。

==============================================
# MHA
==============================================
在MySQL故障切換過程當中,MHA能作到在0~30秒以內自動完成數據庫的故障切換操做,而且在進行故障切換的過程當中,MHA能在最大程度上保證數據的一致性
該軟件由兩部分組成:MHA Manager(管理節點)和MHA Node(數據節點)。
要搭建MHA,要求一個複製集羣中必須最少有三臺數據庫服務器。
爲了儘量的減小主庫硬件損壞宕機形成的數據丟失,所以在配置MHA的同時建議配置成MySQL 5.5的半同步複製。關於半同步複製原理各位本身進行查閱。(不是必須)。

MHA原理
1.從宕機崩潰的master保存二進制日誌事件(binlog events);
2.識別含有最新更新的slave;
3.應用差別的中繼日誌(relay log)到其餘的slave;
4.應用從master保存的二進制日誌事件(binlog events);
5.提高一個slave爲新的master;
6.使其餘的slave鏈接新的master進行復制;

==============================================
# PXC
==============================================
特性以下:
1.同步複製,事務要麼在全部節點提交或不提交。
2.多主複製,能夠在任意節點進行寫操做。
3.在從服務器上並行應用事件,真正意義上的並行複製。
4.節點自動配置。
5.數據一致性,再也不是異步複製。

優勢以下:
1.當執行一個查詢時,在本地節點上執行。由於全部數據都在本地,無需遠程訪問。
2.無需集中管理。能夠在任什麼時候間點失去任何節點,可是集羣將照常工做,不受影響。
3.良好的讀負載擴展,任意節點均可以查詢。

缺點以下:
1.加入新節點,開銷大。須要複製完整的數據。
2.不能有效的解決寫縮放問題,全部的寫操做都將發生在全部節點上。
3.有多少個節點就有多少重複的數據。

侷限性

一、存儲引擎:
基於PXC的複製僅適用於InnoDB存儲引擎。
對其餘存儲引擎的表,包括mysql.*表之類的系統表,任何寫入都不會被複制。
那建立用戶那豈不是沒法同步了?關於這個問題。對於基於DDL方式的語句仍是被支持的。
DDL語句使用基於語句級別的方式來實現(即不使用row模式)。
對mysql.*表的全部已DDL方式的更改都將以語句級別式進行復制。
如:CREATE USER… DDL被複制(語句級)
INSERT INTO mysql.user… myisam存儲引擎,不會被複制,由於非DDL語句
固然也能夠配置wsrep_replicate_myisam參數實現(不建議使用)

二、不支持的查詢:
LOCK TABLES在多主模式中不支持UNLOCK TABLES以及LOCK TABLES
鎖定功能,如GET_LOCK(),RELEASE_LOCK()等也不被支持

三、查詢日誌不能定向到表:
若是啓用查詢日誌記錄,則必須將日誌轉發到文件
使用general_log和general_log_file選擇查詢日誌記錄和日誌文件名稱
log_output = file # Author : Leshami # Blog : https://blog.csdn.net/leshami

四、最大事務大小:
容許的最大事務大小由wsrep_max_ws_rows和wsrep_max_ws_size變量定義
LOAD DATA INFILE方式處理每10000行提交一次。對於大的事務將被分解衆多小型事務

五、集羣樂觀併發控制:
PXC集羣使用樂觀併發控制,事務發出COMMIT可能仍會在該階段停止
能夠有兩個事務寫入相同的行並在單獨的Percona XtraDB集羣節點中提交,而且只有其中一個能夠成功提交。
失敗的將被停止。對於集羣級停止,Percona XtraDB集羣返回死鎖錯誤代碼:
(Error: 1213 SQLSTATE: 40001 (ER_LOCK_DEADLOCK)).

六、因爲可能的提交回滾,XA事務不受支持:

七、硬件配置短板限制:
整個羣集的寫吞吐量受最弱節點的限制。若是一個節點變慢,整個集羣變慢。
若是您對穩定的高性能有要求,那麼它應該由相應的硬件支持。

八、建議的最小羣集大小是3個節點。第三個節點能夠是仲裁者。

九、InnoDB虛假更改功能不受支持。

十、enforce_storage_engine=InnoDB與wsrep_replicate_myisam=OFF(默認)不兼容 。

十一、binlog_rows_query_log_events變量不受支持。

十二、高負載時避免ALTER TABLE … IMPORT / EXPORT

1三、若是DDL語句有問題將破壞集羣。建議使用pt-online-schema-change操做DDL。
 

==============================================
# MGR(MySQL Group Replication)
==============================================
基於傳統異步複製和半同步複製的缺陷——數據的一致性問題沒法保證,MySQL官方在5.7.17版本正式推出組複製(MySQL Group Replication,簡稱MGR)。
由若干個節點共同組成一個複製組,一個事務的提交,必須通過組內大多數節點(N / 2 + 1)決議並經過,才能得以提交。
由3個節點組成一個複製組,Consensus層爲一致性協議層,在事務提交過程當中,發生組間通信,由2個節點決議(certify)經過這個事務,事務纔可以最終得以提交併響應。
引入組複製,主要是爲了解決傳統異步複製和半同步複製可能產生數據不一致的問題。組複製依靠分佈式一致性協議(Paxos協議的變體),實現了分佈式下數據的最終一致性

MySQL官方推出的高可用解決方案,基於原生複製技術,並以插件的方式提供。
複製的管理操做變得更爲自動化
經過Paxos協議提供數據庫集羣節點數據強一致保證
集羣間全部節點可寫入
解決網絡分區致使的腦裂問題,提高複製數據的可靠性。
MGR是Share Nothing,Oracle RAC是Share Everything。
高容錯性,只要不是大多數節點壞掉就能夠繼續工做,有自動檢測機制,當不一樣節點產生資源爭用衝突時,不會出現錯誤,按照先到者優先原則進行處理,而且內置了自動化腦裂防禦機制

MGR優點:
1.不會出現腦裂現象;
2.冗餘能力好,可以保證binlog event至少被複制到超過一半的成員上,主要同時宕機的成員不超過半數便不會致使數據丟失;
3.宕機的服務器重啓後,再也不須要特殊的處理就能夠從新加入組;
4.多節點寫入支持:多寫模式下支持集羣中的全部節點均可以寫入

MGR的限制:
存儲引擎必須爲innodb
每一個表必須提供主鍵
只支持ipv4,網絡需求較高
不支持Savepoints
必須打開GTID特性,二進制日誌格式必須設置爲ROW
二進制日誌不支持binlog event checksum

MGR搭建步驟:
1.安裝搭建MySQL數據。
2.在原有參數文件的基礎上,確認加入如下參數:
binlog-format = ROW
gtid-mode = ON
enforce-gtid-consistency = ON
log-slave-updates = ON
master-info-repository = TABLE
relay-log-info-repository = TABLE
binlog-checksum = NONE
transaction_write_set_extraction =XXHASH64 ###開啓主鍵信息採集功能
loose-group_replication_group_name ="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" ###設置組名
loose-group_replication_start_on_boot =off
loose-group_replication_local_address ="192.168.56.101:33061" ###設置成員的本地地址
loose-group_replication_group_seeds ="192.168.56.101:33061,192.168.56.102:33061,192.168.56.103:33061" ###設置種子成員的地址
loose-group_replication_bootstrap_group =off
loose-group_replication_single_primary_mode=FALSE ###搭建多主模式
loose-group_replication_enforce_update_everywhere_checks= TRUE ###避免未檢測到的外鍵衝突
3.建立受權用戶。
4.安裝插件,啓動複製組
CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='abc_Test123' FOR CHANNEL 'group_replication_recovery';
INSTALL PLUGIN group_replication SONAME 'group_replication.so';
set global group_replication_single_primary_mode=off;
START GROUP_REPLICATION;
5.db二、db3上啓動group_replication:
Db2上mysql命令行上執行啓動:
set global group_replication_allow_local_disjoint_gtids_join=ON;
start group_replication;
select * from performance_schema.replication_group_members;
Db3上啓動group_replication:
set global group_replication_allow_local_disjoint_gtids_join=ON;
start group_replication;
6.查看現有組成員
mysql> SELECT * FROM performance_schema.`replication_group_members`;

平常維護步驟:
一、若是從庫某一節點關閉
stop group_replication;
二、若是全部的庫都關閉後,第一個庫做爲主庫首先執行
set global group_replication_bootstrap_group=ON;
start group_replication;
剩下的庫直接執行便可!
start group_replication;
三、若是主庫故障,會自動從兩個從庫選出一個主庫,主庫啓動後再次執行以下命令後會變成從庫
start group_replication;


==============================================
# 執行計劃
==============================================

select_type
示查詢中每一個select子句的類型(簡單OR複雜)
a. SIMPLE:查詢中不包含子查詢或者UNION
b. 查詢中若包含任何複雜的子部分,最外層查詢則被標記爲:PRIMARY
c. 在SELECT或WHERE列表中包含了子查詢,該子查詢被標記爲:SUBQUERY
d. 在FROM列表中包含的子查詢被標記爲:DERIVED(衍生)用來表示包含在from子句中的子查詢的select,mysql會遞歸執行並將結果放到一個臨時表中。服務器內部稱爲"派生表",由於該臨時表是從子查詢中派生出來的
e. 若第二個SELECT出如今UNION以後,則被標記爲UNION;若UNION包含在FROM子句的子查詢中,外層SELECT將被標記爲:DERIVED
f. 從UNION表獲取結果的SELECT被標記爲:UNION RESULT

SUBQUERY和UNION還能夠被標記爲DEPENDENT和UNCACHEABLE。
DEPENDENT意味着select依賴於外層查詢中發現的數據。
UNCACHEABLE意味着select中的某些 特性阻止結果被緩存於一個item_cache中。


type
表示MySQL在表中找到所需行的方式,又稱「訪問類型」,常見類型以下:
ALL 執行full table scan,這事最差的一種方式
index 執行full index scan,而且能夠經過索引完成結果掃描而且直接從索引中取的想要的結果數據,也就是能夠避免回表,比ALL略好,由於索引文件一般比所有數據要來的小
range 利用索引進行範圍查詢,比index略好
index_subquery 子查詢中能夠用到索引
unique_subquery 子查詢中能夠用到惟一索引,效率比 index_subquery 更高些
index_merge 能夠利用index merge特性用到多個索引,提升查詢效率
ref_or_null 錶鏈接類型是ref,但進行掃描的索引列中可能包含NULL值
fulltext 全文檢索
ref 基於索引的等值查詢,或者表間等值鏈接
eq_ref 錶鏈接時基於主鍵或非NULL的惟一索引完成掃描,比ref略好
const 基於主鍵或惟一索引惟一值查詢,最多返回一條結果,比eq_ref略好
system 查詢對象表只有一行數據,這是最好的狀況

possible_keys
指出MySQL能使用哪一個索引在表中找到記錄,查詢涉及到的字段上若存在索引,則該索引將被列出,但不必定被查詢使用

key
顯示MySQL在查詢中實際使用的索引,若沒有使用索引,顯示爲NULL

key_len
表示索引中使用的字節數,可經過該列計算查詢中使用的索引的長度(key_len顯示的值爲索引字段的最大可能長度,並不是實際使用長度,即key_len是根據表定義計算而得,不是經過表內檢索出的)

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

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

Extra
包含不適合在其餘列中顯示但十分重要的額外信息
Using filesort 將用外部排序而不是按照索引順序排列結果,數據較少時從內存排序,不然須要在磁盤完成排序,代價很是高,須要添加合適的索引
Using temporary 須要建立一個臨時表來存儲結果,這一般發生在對沒有索引的列進行GROUP BY時,或者ORDER BY裏的列不都在索引裏,須要添加合適的索引
Using index 表示MySQL使用覆蓋索引避免全表掃描,不須要再到表中進行二次查找數據,這是比較好的結果之一。注意不要和type中的index類型混淆
Using where 一般是進行了全表/全索引掃描後再用WHERE子句完成結果過濾,須要添加合適的索引
Impossible WHERE 對Where子句判斷的結果老是false而不能選擇任何數據,例如where 1=0,無需過多關注
Select tables optimized away 使用某些聚合函數來訪問存在索引的某個字段時,優化器會經過索引直接一次定位到所須要的數據行完成整個查詢,例如MIN()\MAX(),這種也是比較好的結果之一

==============================================
# 事務、鎖
==============================================
髒讀:一個事務按相同的查詢條件從新讀取之前檢索過的數據,卻發現其餘事務更新後達到了知足其查詢條件的舊數據(此時它還未被提交),這種現象就稱爲「髒讀」。
不可重複讀:一個事務按相同的查詢條件從新讀取之前檢索過的數據,卻發現其餘事務更新後達到了知足其查詢條件的舊數據(此時它已被提交),這種現象就稱爲「不可重複讀」。
幻讀:一個事務按相同的查詢條件從新讀取之前檢索過的數據,卻發現其餘事務插入了知足其查詢條件的新數據(此時它已被提交),這種現象就被稱爲「幻讀」。

事務隔離級別
Read Uncommitted(讀未提交)隔離級別最低
容許髒讀,容許事務查看其它事務所進行的未提交更改,可能讀取到其餘會話中未提交事務修改的數據。

Read Commited(讀已提交)
容許幻讀,容許事務查看其它事務所進行的已提交更改,只能讀取到已經提交的數據。

Repeatable Read(可重複讀)
消除了髒讀、不可重複讀、幻讀,保證事務一致性。
在同一個事務內的查詢都是事務開始時刻一致的,確保每一個事務的讀取結果都是同樣的,默認隔離級別。

Serializable(串行)隔離級別最高
串行化讀,每次讀都須要得到表級共享鎖,讀寫間相互都會阻塞。


一般的鎖範圍:
1.全局鎖(global lock)。
2.表鎖(table lock)。
3.行鎖(row lock)。

InnoDB行鎖範圍(粒度):
1.record lock. 單個記錄上的鎖
2.gap lock. 間隙鎖,鎖定一個範圍,但不包含記錄自己
3.next-key lock = record lock + gap lock. 鎖定一個範圍,而且鎖定記錄自己

Record Lock 老是會去鎖住索引記錄,若是innodb存儲引擎表在創建的時候沒有設置任何一個索引,並且查詢的時候沒有使用到索引,那麼這時就會致使表鎖。
Next-Key Lock是結合了Gap Lock和Record Lock的一種鎖定算法,在Next-Key Lock算法下,innodb對於行的查詢都是採用這種鎖定算法。例如一個索引有10,11,13,20這4個值,那麼該索引可能被Next-Key Locking的範圍爲:
(- &,10]
(10,11]
(13,20]
(20,+ &)

採用Next-Key Lock的鎖定技術稱爲Next-Key Locking。這種設計的目的是爲了解決幻讀(Phantom Problem)。利用這種鎖定技術,鎖定的不是單個值,而是一個範圍。

注:當查詢的索引含有惟一屬性時,innodb存儲引擎會對Next-Key Lock進行優化,將其降級爲Record Lock,即鎖住索引記錄自己,而再也不是範圍。

注意:
對於惟一索引,其加上的是Record Lock,僅鎖住記錄自己。但也有特別狀況,那就是惟一索引由多個列組成,而查詢僅是查找多個惟一索引列中的其中一個,那麼加鎖的狀況依然是Next-key lock。

對於輔助索引,其加上的是Next-Key Lock,鎖定的是範圍,包含記錄自己。
另外若是使用相等的條件給一個不存在的記錄加鎖,innodb也會使用Next-key lock

特別注意:
innodb存儲引擎是經過給索引上的索引項加鎖來實現,這意味着:只有經過索引條件檢索數據,innodb纔會使用行鎖,不然,innodb將使用表鎖。固然這種說法是在表沒有主鍵或者沒有任何索引的狀況下。若是一個表有主鍵,沒有其餘的索引,檢索條件又不是主鍵,SQL會走聚簇索引的全掃描進行過濾,因爲過濾是由MySQL Server層面進行的。所以每條記錄,不管是否知足條件,都會被加上X鎖。可是,爲了效率考量,MySQL作了優化,對於不知足條件的記錄,會在判斷後放鎖,最終持有的,是知足條件的記錄上的鎖,可是不知足條件的記錄上的加鎖/放鎖動做不會省略。同時,優化也違背了2PL的約束。

RC級別下,只有record lock,沒有next key lock。
RR級別下,除非primary key或unique key是record lock,其他都是next key lock。

==============================================
# pt工具
==============================================
pt-heartbeat 監控mysql複製延遲
pt-online-schema-change 在線修改表結構
pt-table-checksum 校驗主從複製一致性
pt-table-sync 同步表數據

pt-online-schema-change工具的使用限制:
1)若是修改表有外鍵,除非使用 --alter-foreign-keys-method 指定特定的值,不然工具不予執行
2)被修改表必需要有主鍵,不然報錯:Cannot chunk the original table `houyi`.`ga`: There is no good index and the table is oversized. at ./pt-online-schema-change line 5353.
3)被修改表上不能有針對after delete|insert|update三個觸發器,不然修改表結構操做失敗

online ddl的原理以下:
一、建立一個和原來表結構同樣的臨時表並ddl
二、鎖住原表,全部數據都沒法寫入(insert,update,delete)
三、將原表數據寫入到臨時表中(經過insert ...select方式)
四、寫入完後,重命名臨時表和原表名稱
五、刪除原表,釋放鎖

pt-online-schema-change在線ddl原理以下:
一、建立一個和原來表結構同樣的臨時表並ddl
二、將原表數據寫入到臨時表中(經過insert ...select方式),而且在原表上建立觸發器,若是原表有數據寫入,經過觸發器方式將新增的數據寫入臨時表中(前提該表以前沒有觸發器)
三、寫入完後,重命名臨時表和原表名稱
四、刪除原表

==============================================
# 備份恢復
==============================================
mysqldump實現原理
1.修改session級別的sql_mode爲空,避免可能有些些sql_mode值會對備份產生影響
2.強制刷新表緩存到磁盤,並關閉表。若是另外一個會話已經加上表鎖,那麼該語句會被阻塞
3.調用 flush tables with read lock 對整個實例加全局讀鎖
4.開啓快照讀,在session級別將隔離級別設置成RR,由於開啓一個一致性快照事務,須要在RR隔離級別,獲取此時的快照(僅對innodb表起做用)
5.備份非innodb表數據(*.frm,*.myi,*.myd等)
6.非innodb表備份完畢後,釋放FTWRL鎖
7.逐一備份innodb表數據
8.表備份結束,回滾到保存點sp,以釋放select *語句產生的MDL鎖,若是不回滾,後續整個備份過程當中沒法對該表執行DDL操做
9.備份完成後,釋放該保存點

Xtrabackup實現原理
1.innobackupex 在啓動後,會先 fork 一個進程,啓動 xtrabackup進程,而後就等待 xtrabackup 備份完 ibd 數據文件;
2.xtrabackup 在備份 InnoDB 相關數據時,是有2種線程的,1種是 redo 拷貝線程,負責拷貝 redo 文件,1種是 ibd 拷貝線程,負責拷貝 ibd 文件;redo 拷貝線程只有一個,在 ibd 拷貝線程以前啓動,在 ibd 線程結束後結束。xtrabackup 進程開始執行後,先啓動 redo 拷貝線程,從最新的 checkpoint 點開始順序拷貝 redo 日誌;而後再啓動 ibd 數據拷貝線程,在 xtrabackup 拷貝 ibd 過程當中,innobackupex 進程一直處於等待狀態(等待文件被建立)。
3.xtrabackup 拷貝完成idb後,通知 innobackupex(經過建立文件),同時本身進入等待(redo 線程仍然繼續拷貝);
4.innobackupex 收到 xtrabackup 通知後,執行FLUSH TABLES WITH READ LOCK (FTWRL),取得一致性位點,而後開始備份非 InnoDB 文件(包括 frm、MYD、MYI、CSV、opt、par等)。拷貝非 InnoDB 文件過程當中,由於數據庫處於全局只讀狀態,若是在業務的主庫備份的話,要特別當心,非 InnoDB 表(主要是MyISAM)比較多的話整庫只讀時間就會比較長,這個影響必定要評估到。
5.當 innobackupex 拷貝完全部非 InnoDB 表文件後,通知 xtrabackup(經過刪文件) ,同時本身進入等待(等待另外一個文件被建立);
6.xtrabackup 收到 innobackupex 備份完非 InnoDB 通知後,就中止 redo 拷貝線程,而後通知 innobackupexredo log 拷貝完成(經過建立文件);
7.innobackupex 收到 redo 備份完成通知後,就開始解鎖,執行 UNLOCK TABLES;
8.最後 innobackupex 和 xtrabackup 進程各自完成收尾工做,如資源的釋放、寫備份元數據信息等,innobackupex 等待 xtrabackup 子進程結束後退出。

==============================================
# 常見問題
==============================================
某人曰,在數據檢索的條件中使用!=操做符時,存儲引擎會放棄使用索引。
理由:由於檢索的範圍不能肯定,因此使用索引效率不高,會被引擎自動改成全表掃描。你承認他的說法嗎?

答:一般狀況下,這個說法是正確的。固然,也有特殊狀況,話不能說絕對了。
有一個測試表共80萬條數據,其中type列只有一、2兩個值,分別佔比97%和3%。
這種狀況下,查詢條件 WHERE type != 1,是有可能也能夠走索引的。
下面是兩個SQL的執行計劃:
mysql> desc select * from t1 where type = 1\G
**************** 1. row ****************
id: 1
select_type: SIMPLE
table: t1
partitions: NULL
type: ref
possible_keys: type
key: type
key_len: 4
ref: const
rows: 399731
filtered: 100.00
Extra: NULL

mysql> desc select * from t1 where type != 1\G
**************** 1. row ****************
id: 1
select_type: SIMPLE
table: t1
partitions: NULL
type: ref
possible_keys: type
key: type
key_len: 4
ref: const
rows: 10182
filtered: 100.00
Extra: NULL

type數據分佈
mysql> select type, count(*) as cnt from t1 group by type order by cnt;
+------+--------+
| type | cnt |
+------+--------+
| 2 | 38304 |
| 1 | 761690 |
+------+--------+

MySQL在高併發時有什麼過載保護的方法?
一、在前端Nginx層/中間件中限流,控制對MySQL的請求數。
二、控制MySQL的參數max_connections/max_user_connections,防止太高併發。
三、利用pt-kill等工具,及時殺掉引起性能問題的SQL。
四、根據服務器的壓力狀況,適當調整MySQL的innodb_thread_concurrency參數。
五、快速構建從庫,緩解主庫讀壓力。
六、適當調整max_execution_time=N。當SQL語句超過N秒,不予執行。
七、儘快優化慢SQL。

在大表執行ddl的過程當中,若臨時中斷,會發生什麼情況,須要特別處理嗎 ?
前提說明:MySQL5.7.2三、innodb表、「雙1」
一、添加/刪除列,採用copy的方式
1.一、ctrl+c。在當前session中,手動執行ctrl+c。無影響,而且會自動刪除產生的臨時文件。
1.二、kill -9。在執行ddl的時候,服務器發生意外宕機或者手動執行kill -9。待MySQL啓動後,則會自動執行InnoDB Recovered流程。而且不會刪除產生的臨時文件,須要手工處理。
二、添加/刪除索引,採用INPLACE方式
2.一、ctrl+c。同1.1
2.二、kill -9。不會刪除臨時文件,也不會執行InnoDB Recovered流程而且報錯 Operating system error number 2 in a file operation ....OS error: 71
在開始執行alter table的過程當中,在沒有結束的時候,並不會寫入到binglog文件中。

如何優化一條慢SQL
1.表設計、數據類型是否合理。
2.SQL寫法是否正確。
3.表的統計信息是否正確。
4.看執行計劃,判斷上面有沒有合適的索引。

MySQL數據庫cpu飆升到500%的話該怎麼處理?
當 cpu 飆升到 500%時,先用操做系統命令 top 命令觀察是否是 mysqld 佔用致使的,若是不是,找出佔用高的進程,並進行相關處理。若是是 mysqld 形成的, show processlist,看看裏面跑的 session 狀況,是否是有消耗資源的 sql 在運行。找出消耗高的 sql,
看看執行計劃是否準確, index 是否缺失,或者實在是數據量太大形成。通常來講,確定要 kill 掉這些線程(同時觀察 cpu 使用率是否降低),等進行相應的調整(好比說加索引、改 sql、改內存參數)以後,再從新跑這些 SQL。也有多是每一個 sql 消耗資源並很少,可是忽然之間,
有大量的 session 連進來致使 cpu 飆升,這種狀況就須要跟應用一塊兒來分析爲什麼鏈接數會激增,再作出相應的調整,好比說限制鏈接數等前端

相關文章
相關標籤/搜索