MySQL相關 (想到什麼寫什麼,持更 )

2021-10-09 08:41:28 字數 4388 閱讀 7869

普通索引和唯一索引

innodb建立索引時,只可以建立b+tree索引,是不可以建立hash索引的,而hash索引相對於b+tree索引,雖然無法實現排序,範圍檢索的效果,但是在等值檢索時比b+tree索引的效率高很多。

所以innodb在b+tree索引的基礎上又新增了自適應hash索引,只不過這個索引無法通過手動建立,是通過innodb儲存引擎在執行時自己建立的,對於使用者來說是透明的,

innodb會監控堆表上二級索引的查詢,如果發現某個二級索引頻繁訪問,那麼就會認為這個二級索引是熱點資料,就會針對這個二級索引建立hash索引,下一次再檢索時就可以直接通過hash索引檢索。

innodb認為最近連續三次被訪問的二級索引是熱點資料,就會自動建立hash索引。

缺點是:會占用一部分innodb的緩衝池,只適合等值查詢,不支援範圍查詢;極端情況下才有效,如果不是連續讀相同索引就無效。

插入快取是針對非聚簇索引而言的,因為聚簇索引一般都是有順序的,所以在執行批量插入時,第一條語句插完之後後面的資料所在頁基本上都和第一條資料在同一頁上,或者相鄰頁,根據資料庫預讀的特性。

所以批量插入的時候只需載入依次頁就可以完成多條資料的插入操作。但非聚簇索引基本上是無序的,離散的,所以每次插入的時候就需要離散地訪問非聚簇索引頁,就降低插入的效能。

innodb為解決這個問題就新增了插入快取功能,對於非聚簇索引插入或更新,不是直接更新到索引頁,而是先判斷更新的非聚簇索引是否存在緩衝池中,如果在就直接插入到緩衝池,如果不存在就先放入緩衝池。然後再以一定的頻率將緩衝池中的快取和非聚簇索引頁的資料進行合併操作。由於在乙個索引頁,所以通常可以將多個插入操作合併成乙個操作,減少了非聚簇索引頁的io操作。

插入快取的條件

索引必須是非聚簇索引(聚簇索引是有序的,不需要快取)

索引不是唯一的(唯一的情況就失去了意義,只能達到延遲的效果,並不能減少io次數)

插入快取的缺點是需要占用一部分緩衝池的空間,可以通過配置ibuf_pool_size_pre_max_size進行配置,如值為3,則最大只能使用1/3的緩衝池空間。

innodb在記憶體中維護了多個緩衝池,用來快取近期訪問的資料和索引。緩衝池的配置:

innodb_buffer_pool_size:緩衝池大小,建議設定成系統總記憶體的70%~80%

innodb_buffer_pool_instance:緩衝池的個數,建議設定成cpu核數

innodb_flush_log_at_trx_commit:緩衝池中資料如何刷盤,設定為1,資料不丟失,設定為2,最多丟失1秒鐘,但效能較高

緩衝池的記憶體管理:

緩衝池內部通過list管理資料,採用lru演算法(最近不訪問)淘汰資料,當緩衝池慢了,會刪除最近沒有被訪問的資料,而插入緩衝池時,也不算插入list的頭部或尾部,而是插入list的中間。因為頭部是熱點資料,尾部是即將淘汰的資料,採用保險策略將新的資料插入中間比較合理。list中儲存的以頁為單位,所以插入和刪除都是以頁為單位的。lru演算法將整個list的5/8作為new list,剩下3/8作為old list,old list就是潛在的會被淘汰的資料,如果old list中的資料被訪問到了,就會插入到new list到頭部。

innodb的所有操作幾乎都是在緩衝池中實現,將磁碟中的資料載入到緩衝池中,然後再進行下一步操作,更新的時候也是直接更新緩衝池中的資料,然後再按一定頻率重新整理到磁碟。

緩衝池還有乙個預讀功能,預讀功能是當innodb執行了一次io操作載入了一頁或多頁之後,會預計下一次需要載入到頁面資料,而提前將資料載入到緩衝池,就可以避免下一次再進行io操作。

預讀有兩種預讀演算法:線性預讀和隨機預讀

**線性預讀:**按page的順序進行預讀,預讀page的個數可以通過配置設定。

**隨機預讀:**當某一塊extent中的某一頁或某幾頁被載入之後,會將這個extent中的所有page都載入到緩衝池。

double write是為了提公升innodb的可靠性,確保資料不會丟失。主要分成兩部分組成:一部分是記憶體中的double write buffer,大小為2m,一部分是磁碟上共享表空間(ibdata)中連續的兩個區,也就是128頁,大小為2m。

當觸發資料緩衝池中的髒頁重新整理時,並不是直接寫入磁碟檔案,而是先拷貝到double write buffer。

然後從double write buffer中分兩次寫入磁碟共享表空間中(連續儲存、順序寫效率高)每次寫1m

第二步完成後,再將double write buffer中的髒頁資料寫入實際各個表空間檔案(離散寫);髒頁資料持久化完成之後就可以標記double write區的資料可以被覆蓋了。

為什麼要double write

關於io最小單位,order也是8k,mysql是一頁也就是16k;檔案系統的io最小單位是4k,也有的1k,磁碟io的最小單位是512位元組

當需要將髒頁16k的資料寫入到磁碟檔案時,假設每次是4k,那麼就需要進行四次物理寫的操作才能完成

如果在執行了2次物理寫之後,系統出現故障,就會導致磁碟中已經被寫入了乙個不完整的資料頁(資料頁被破壞)

系統恢復時,redo log只能加上舊,檢驗完整的資料頁恢復乙個髒塊,不能修復壞掉的資料頁,從而導致資料不一致(redo log記錄的是對頁的物理修改)

double write的崩潰恢復

如果作業系統將頁寫入磁碟的過程宕機,恢復的時候可以從共享表空間的double write檔案中找到該頁的最近的副本,將其複製到表空間檔案,再通過 redo log就可以完成恢復操作

為什麼log的寫不需要通過double write呢?

因為log的寫入單位是512個位元組,所以不存在資料損壞

為什麼不直接從double write寫入data page?

因為double write也是檔案,而data page又是離散的,從double write中讀取資料寫入data page顯然沒有從快取中直接寫入data page快。

參見另一篇博文mysql持久化和主從複製

對於普通索引,查詢滿足條件的第乙個記錄後,需要查詢下乙個記錄,直到碰到第乙個不滿足條件的記錄

對於唯一索引,由於索引定義了唯一性,查詢第乙個滿足條件的記錄後,就會停止繼續檢索。

其帶來的效能影響差距很小,因為innodb是按頁讀寫的,在需要讀一條記錄時,並不是將這個記錄本身從磁碟中讀出來,而是以頁為單位,將其整體讀入記憶體。在innodb中,每個資料頁的大小預設是16kb。

因為引擎是按頁讀寫的,所以找到滿足條件的記錄時,它所在的資料頁就都在記憶體裡了,對於普通索引來說,要多做的那一次「查詢和判斷下一條記錄」的操作,就只需要一次指標尋找和一次計算。

當需要更新乙個資料頁時,如果資料頁在記憶體中就直接更新,如果這個資料頁還沒有在記憶體中的話,在不影響資料一致性的前提下,innodb會將這些更新操作快取在change buffer中,這樣就不需要從磁碟中讀入這個資料頁了。在下次需要訪問這個資料頁時,將資料頁讀入記憶體,然後執行change buffer中與這個頁有關的操作。通過這種方式能保證這個數字邏輯的正確性。

雖然叫change buffer,實際上是可以持久化的資料,change buffer在記憶體中有拷貝,也會被寫入到磁碟。

將change buffer中的操作應用到原資料頁,得到更新結果的過程稱為merge。除了訪問這個資料頁會觸發merge以外,系統有後台執行緒會定期merge。在資料庫正常關閉過程中,也會執行merge。

將更新操作先記錄在change buffer,減少讀磁碟,語句的執行速度會得到明顯的提公升。而且資料讀入記憶體會占用buffer pool,這種方式還能避免占用記憶體,提高記憶體利用率。

什麼條件下可以使用change buffer

對於唯一索引來說,所有更新操作都要先判斷是否違反唯一性約束,這必須要將資料讀入記憶體才能判斷,這時就直接更新記憶體更快,不需要用change buffer。

對於普通索引,change buffer用的是buffer pool裡的記憶體,因此不能無限增大,可以通過innodb_change_buffer_max_size引數來動態設定。

change buffer減少了隨機磁碟訪問,所以對更新效能提公升更明顯。

change buffer的使用場景

change buffer只限於用在普通索引的場景下。

因為merge的時候是真正進行資料更新的時刻,而change buffer的主要目的就是將記錄的變更動作快取下來,所以在乙個資料頁做merge之前,change buffer記錄的變更越多,收益越大。

對於寫多讀少的業務來說change buffer的使用效果最好,常見賬單類,日誌類的系統。

redo log和change buffer

redo log主要節省的是隨機寫磁碟的io消耗,而change buffer主要節省的則是隨機讀磁碟的io消耗。

亂七八糟想到什麼記什麼10

r reboot h halt c cancel time 無指定,預設相當於 1 centos7 now 立刻,相當於 0 相對時間表示法,幾分鐘之後 例如 3 hh mm 絕對時間表示,指明具體時間 利用screen 可以實現會話管理,如 新建會話,共享會話等 開啟了乙個虛擬終端視窗,長時間的執...

亂七八糟想到什麼記什麼6

對於經常執行的較長的命令,可以將其定義成較短的別名,以方便執行 顯示當前shell程序所有可用的命令別名 alias建立常用操作 alias name value unalias a name name unalias a 取消所有別名將常用目錄定義為別名命令 15 51 42 root c8 cd...

不知道總結什麼的總結以及一些想到什麼寫什麼的東西

不管怎麼說2020也算是過去了,而事實上2021的第乙個月也將在十多個小時候宣告離去,理論上來說,對於一篇應該算是自我總結的東西而言,這時候是該談一些什麼時間流逝或是一些對別的什麼雜七雜八東西的感慨,但憑心而論,這種東西於我而言並沒有什麼特別的觸動。就好比那個關於你是否後悔你所做的一些決定的老話題一...