關於MySQL的一些零散的知識

索引下推:如果查詢條件中有幾個字段都命中了聯合索引,根據聯合索引裏面的值提前進行判斷條件,可以減少回表的次數。

mysql的內存是基於頁的緩存,每一個頁是16kb.更新會涉及到change buffer,對於普通索引,如果要操作的頁不在內存中,需要在change buffer中紀錄當前的操作,並記錄在WAL裏。後續通過merge操作將數據同步到磁盤。後續讀數據時,內存中有數據,直接從內存中返回,如果內存中不存在的話,將磁盤中的數據讀出來,再配合change buffer的變動去得到最新的數據。change buffer的優點時,將多次寫磁盤IO操作減少,增加寫數據的吞吐量。

 

-- 查詢當前數據庫實例中連接的用戶
show processlist;


-- 查詢執行時間超過60s的事務。
select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started)) > 60;

-- 重建表 (recreate)
alter table T engine=InnoDB;

analyze table t; -- 其實不是重建表,只是對錶的索引信息做重新統計,沒有修改數據,這個過程中加了 MDL 讀鎖;

optimize table t; -- recreate+analyze


-- 對整個數據庫實例加鎖,只能讀不能寫
Flush tables with read lock;

-- 整個數據庫實例只能讀
set global readonly=true;

-- 做表進行DDL,DML時,可以設置超時時間,避免將表長時間鎖住
ALTER TABLE tbl_name NOWAIT add column ...   (沒有獲取到鎖直接拋出異常,不等待)
ALTER TABLE tbl_name WAIT N add column ...  (沒有獲取到鎖等待N秒,N秒內沒有獲取到鎖,拋出異常)


-- 開始一個事務

start transaction; (需要到第一個執行sql時纔會開啓一個事務)
start transaction with consistent snapshot;(直接開啓一個事務)


-- 數據更新時,讀取數據爲當前讀,讀取的是最新版本的那一條數據。
-- 如果select語句加上鎖的話,也是當前讀

-- mysql讀取數據是基於數據頁爲單位的,一個數據頁16kb,查詢時會以數據頁的形式返回。

redolog和binlog存在關聯關係,通過XID來實現的,兩個日誌都保存了一個XID。

sort by 排序分爲兩種.如果要查詢的字段的所有長度小於max_length_for_sort_data的話,就是用全字段排序,否則使用排序字段排序
排序時如果內存不夠的話,需要開闢多個tmp_sort_file來進行排序,sort_buffer_size越小,sort_file越多。後續通過歸併算法來將結果合併。
1.全字段排序: 將查詢的接口都丟到排序內存或者排序文件中。後續基於要排序的字段排完後直接返給server層
2.rowid排序: 將需要排序的字段和主鍵id丟到內存或者排序文件中。

show index from t; 顯示錶的索引信息
analyze table t;  重新分析表的索引信息

對於普通索引的更新操作,當要更新的數據行在內存中存在時,就直接進行更新。如果不在內存中的話,將更新操作緩存在change buffer中,change buffer也會進行持久化操作。
在下次查詢數據頁的時候,將change buffer中作用於該數據頁中的操作,這個操作叫做merge。除了訪問數據會進行merge以外,系統後臺線程會定期merge,在數據庫正常shutdown時,
也會進行merge操作。
而唯一索引需要判斷對應的數據是否要進行更新,必須要將數據行所在的數據頁讀到內存中,如果操作的數據不在內存中的話,效率比普通索引的更新操作要慢一點。
change buffer場景用在寫多讀少的場景比較好,不然更新過後就讀,會導致頻繁的merge操作。
我們在選擇索引時,在業務允許的情況下。能用普通索引就用普通索引,儘量不用唯一索引


髒頁進行刷盤的4個時機:
1.redolog滿了,需要清除一些redolog,這時要把redolog相關的髒頁頁進行flush刷盤操作
2.內存不夠了,需要淘汰掉一些數據頁,如果被淘汰的數據頁是髒頁,這個時候需要進行刷盤
3.mysql在空閒的時候,也會進行髒頁的刷盤
4.在數據庫正常關閉的情況下,也需要進行髒頁的刷盤


在需要隨機顯示數據庫的幾條數據時,不使用order by rand();通過計算所有數據的總條數來進行limit更好,表的掃描行數更低。
對索引字段做函數操作,可能會破壞索引值的有序性,因此優化器就決定放棄走樹搜索功能。
1.對字段進行了函數操作
2.隱式類型轉換
3.隱式字符編碼轉換
上面三個本質都是對where a = 3中的a字段進行了處理,優化器就不會走a索引了。

查詢緩慢的原因:
1.等MDL鎖,可以通過show processlist來查看語句的執行狀態
2.等待flush,flush鎖住
3.等行鎖
4.查詢沒有走到索引
5.低版本事務查詢數據時,因爲當前數據的事務版本過高,要執行更多個undolog進行數據還原

避免幻讀可以將事務隔離級別設置爲可重複讀,通過引入間隙鎖來鎖住還沒有插入數據的間隙,避免其他事務插入數據的問題。
可重複讀用的是next-key lock,爲前開後閉區間。使用可重複讀容易導致死鎖,一般使用的是讀提交,並且將binlog格式設置爲raw。

可重複讀隔離級別下的加鎖原則。
1.加鎖的基本單位是next-key lock (左開右閉)
2.查找過程中訪問到的對象(對象指索引,加鎖時對索引加鎖)才加鎖 (索引覆蓋的場景,非聚集索引鎖住了不會影響到聚集索引)
3.索引上的等值查詢,給唯一索引加鎖時,next-key lock退化爲行鎖,因爲不可能存在兩個值同樣的唯一索引,對這個索引值進行操作的話不會導致幻讀
4.索引上的等值查詢,向右遍歷時且最後一個值不滿足等值條件時,next-key lock退化爲間隙鎖(左開右開)
5.唯一索引上的範圍查詢會訪問到不滿足條件的第一個值爲止
tips:lock in share mode 只鎖覆蓋索引,但是如果是 for update 就不一樣了。 執行 for update 時,系統會認爲你接下來要更新數據,因此會順便給主鍵索引上滿足條件的行加上行鎖。


讀提交隔離級別的一個優化,對應的行鎖在語句執行完之後就會釋放,不會等到事務提交之後再釋放

binlog的寫入機制:
在一個事務執行時,將本次事務中對數據的操作先寫到binlog cache中,(binlog cache在每個線程中都有,如果binlog大小超過binlog cache,會寫到磁盤上)
是事務提交時,將binlog write到磁盤的page cache中,然後再將page cache中的binlog fsync到磁盤中。
fsync的時機由參數sync_binlog控制。
sync_binlog=0 的時候,表示每次提交事務都只 write,不 fsync;
sync_binlog=1 的時候,表示每次提交事務都會執行 fsync;
sync_binlog=N(N>1) 的時候,表示每次提交事務都 write,但累積 N 個事務後才 fsync。

redolog的寫入機制:
事務在執行過程中,會先將redo log寫在redo log buffer(redo log buffer是整個mysql共享的)中,後續再將buffer中的redo log write到文件系統緩存,最後再fsync到磁盤上。
可以通過innodb_flush_log_at_trx_commit參數來進行控制.
設置爲 0 的時候,表示每次事務提交時都只是把 redo log 留在 redo log buffer 中.
設置爲 1 的時候,表示每次事務提交時都將 redo log 直接持久化到磁盤.
設置爲 2 的時候,表示每次事務提交時都只是把 redo log 寫到 page cache.

mysql中有個後臺線程,每秒鐘都會檢測redo log buffer中的redo log,write到文件系統緩存,再fsync到磁盤中
如果redo log buffer中的redo log大小超過了innodb_log_buffer_size的一半,後臺線程會主動寫盤,將redo log buffer中的log write到文件系統緩存,最後再fsync到磁盤上。
如果innodb_flush_log_at_trx_commit配置的是1,另一個事務提交時,會把其他還未提交的事務的redo log也一併寫到磁盤。
redo log的prepare文件會fsync到磁盤上,而commit文件只需要write到文件系統緩存,因爲在進行crash recovery時,通過binlog和redo log的prepare文件就行了。


組提交機制:redolog和binlog在fync刷盤時,可能會將多個日誌一起進行提交,這樣可以大幅度降低磁盤的 IOPS 消耗
有兩個fsync刷盤的參數策略:
binlog_group_commit_sync_delay:表示延遲多少微秒後才調用 fsync.
binlog_group_commit_sync_no_delay_count:表示累積多少次以後才調用 fsync.
這兩個條件是或的關係,也就是說只要有一個滿足條件就會調用 fsync.

-- 相關參數
innodb_lock_wait_timeout (等待鎖的超時時間)
innodb_deadlock_detect (死鎖自動取消某一個死鎖獲得的鎖資源)
innodb_change_buffer_max_size (change buffer佔buffer pool的比例大小)
long_query_time 慢sql判斷閾值
transaction_isolation  事務的隔離級別
innodb_io_capacity 默認200 磁盤io的能力
innodb_max_dirty_pages_pct  默認75% 髒頁比例上限
innodb_flush_neighbors  刷髒頁時是否一同刷掉旁邊的髒頁,數據頁是用前後指針進行關聯的,所有有前後兩個髒頁需要檢測,並且是遞歸的。
innodb_file_per_table 表數據的存放位置,OFF表示的是,表的數據放在系統共享表空間,也就是跟數據字典放在一起。
ON表示的是,每個 InnoDB 表數據存儲在一個以 .ibd 爲後綴的文件中。推薦設置成ON
sort_buffer_size 排序內存buffer的大小
max_length_for_sort_data 需要查詢的字段的長度總和大小。 判斷在sort_buffer中排序的字段是否是全字段
tmp_table_size 內存臨時表的大小,超過這個大小的就要使用磁盤臨時表
internal_tmp_disk_storage_engine 磁盤臨時表的默認引擎
binlog_cache_size 單個線程的binlog緩存大小
sync_binlog  binlog的刷盤策略
innodb_log_buffer_size redo log的緩存大小
innodb_flush_log_at_trx_commit  redolog的刷盤策略

optimizer_trace: 查看整個執行計劃以及對於多種索引方案是如何選擇的。
相關參數參數:number_of_tmp_files 用於排序的臨時文件的個數 examined_rows:滿足條件的數據行數

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