【MySQL】必備終極技能篇(持續更新...)

1、事務

1、1 基本概念

  • 數據庫事務是構成單一邏輯工作單元的操作集合

注意點:

  • 1 、數據庫事務可以包含一個或多個數據庫操作,但這些操作構成一個邏輯上的整體
  • 2、構成邏輯整體的這些數據庫操作,要麼全部執行成功,要麼全部不執行
  • 3、構成事務的所有操作,要麼全都對數據庫產生影響,要麼全都不產生影響,即不管事務是否執行成功,數據庫總能保持一致性狀態
  • 4、併發操作下,事務的控制尤爲關鍵

1、2 人人都知道事務的四大特性:ACID

  • 原子性(Atomicity):事務中的所有操作作爲一個整體像原子一樣不可分割,要麼全部成功,要麼全部失敗。
  • 一致性(Consistency):事務的執行結果必須使數據庫從一個一致性狀態到另一個一致性狀態。一致性狀態是指:
    • 1.系統的狀態滿足數據的完整性約束(主碼,參照完整性,check約束等)
    • 2.系統的狀態反應數據庫本應描述的現實世界的真實狀態,比如轉賬前後兩個賬戶的金額總和應該保持不變。
  • 隔離性(Isolation):併發執行的事務不會相互影響,其對數據庫的影響和它們串行執行時一樣。比如多個用戶同時往一個賬戶轉賬,最後賬戶的結果應該和他們按先後次序轉賬的結果一樣。
  • 持久性(Durability):事務一旦提交,其對數據庫的更新就是持久的。任何事務或系統故障都不會導致數據丟失。

1、3 但他們的實現原理是什麼?

  • 事務的原子性是通過 undo log 來實現的

    • Undo Log是爲了實現事務的原子性,在MySQL數據庫InnoDB存儲引擎中,還用Undo Log來實現多版本併發控制(簡稱:MVCC)
    • 在操作任何數據之前,首先將數據備份到一個地方(這個存儲數據備份的地方稱爲Undo Log)。然後進行數據的修改。如果出現了錯誤或者用戶執行了ROLLBACK語句,系統可以利用Undo Log中的備份將數據恢復到事務開始之前的狀態

      注意:undo log是邏輯日誌,可以理解爲:
    • 當delete一條記錄時,undo log中會記錄一條對應的insert記錄
    • 當insert一條記錄時,undo log中會記錄一條對應的delete記錄
    • 當update一條記錄時,它記錄一條對應相反的update記錄
  • 事務的持久性是通過 redo log 來實現的

    和Undo Log相反,Redo Log記錄的是新數據的備份。在事務提交前,只要將Redo Log持久化即可,不需要將數據持久化。當系統崩潰時,雖然數據沒有持久化,

    但是Redo Log已經持久化。系統可以根據Redo Log的內容,將所有數據恢復到最新的狀態

    通過sql:SELECT @@innodb_flush_log_at_trx_commit可以查看當前表的undo log使用的哪一種
    在這裏插入圖片描述
    在這裏插入圖片描述
    當設置爲0,該模式速度最快,但不太安全,mysqld進程的崩潰會導致上一秒鐘所有事務數據的丟失。(原因是數據第一部存儲在了日誌內存中)

    當設置爲1,該模式是最安全的,但也是最慢的一種方式。在mysqld 服務崩潰或者服務器主機crash的情況下,binary log 只有可能丟失最多一個語句或者一個事務(原因是數據直接存入了磁盤進行了持久化)

    當設置爲2,該模式速度較快,也比0安全,只有在操作系統崩潰或者系統斷電的情況下(原因是數據第一部存儲在了系統內存中),上一秒鐘所有事務數據纔可能丟失。

  • 事務的隔離性是通過 (讀寫鎖+MVCC)來實現的

    • 後面的模塊進行介紹
  • 事務的一致性是通過原子性,持久性,隔離性來實現的!

Mysql事務的隔離級別:(隔離級別從上到下,由低到高)
在這裏插入圖片描述

2、日誌

MySQL中有七種日誌文件,分別是:

2、1 重做日誌(redo log)

  • 1、作用

    • 確保事務的持久性。防止在發生故障的時間點,尚有髒頁未寫入磁盤,在重啓mysql服務的時候,根據redo log進行重做,從而達到事務的持久性這一特性。
  • 2、內容

    • 物理格式的日誌,記錄的是物理數據頁面的修改的信息,其redo log是順序寫入redo log file的物理文件中去的。
  • 3、什麼時候產生
    事務開始之後就產生redo log,redo log的落盤並不是隨着事務的提交才寫入的,而是在事務的執行過程中,便開始寫入redo log文件中。

  • 4、什麼時候釋放

    • 當對應事務的髒頁寫入到磁盤之後,redo log的使命也就完成了,重做日誌佔用的空間就可以重用(被覆蓋)。
  • 5、對應的物理文件

    • 默認情況下,對應的物理文件位於數據庫的data目錄下的ib_logfile1&ib_logfile2

      innodb_log_group_home_dir 指定日誌文件組所在的路徑,默認./ ,表示在數據庫的數據目錄下。innodb_log_files_in_group 指定重做日誌文件組中文件的數量,默認2

      關於文件的大小和數量,由一下兩個參數配置

      innodb_log_file_size 重做日誌文件的大小。

      innodb_mirrored_log_groups 指定了日誌鏡像文件組的數量,默認1

  • 6、其他

    • 很重要一點,redo log是什麼時候寫盤的?前面說了是在事物開始之後逐步寫盤的。

      之所以說重做日誌是在事務開始之後逐步寫入重做日誌文件,而不一定是事務提交才寫入重做日誌緩存,

      原因就是,重做日誌有一個緩存區Innodb_log_buffer,Innodb_log_buffer的默認大小爲8M(這裏設置的16M),Innodb存儲引擎先將重做日誌寫入innodb_log_buffer中。

2、2回滾日誌(undo log)

  • 1、作用

    • 保存了事務發生之前的數據的一個版本,可以用於回滾,同時可以提供多版本併發控制下的讀(MVCC),也即非鎖定讀
  • 2、內容

    • 邏輯格式的日誌,在執行undo的時候,僅僅是將數據從邏輯上恢復至事務之前的狀態,而不是從物理頁面上操作實現的,這一點是不同於redo log的。
  • 3、什麼時候產生

    • 事務開始之前,將當前是的版本生成undo log,undo 也會產生 redo 來保證undo log的可靠性
  • 4、什麼時候釋放

    • 當事務提交之後,undo log並不能立馬被刪除,

      而是放入待清理的鏈表,由purge線程判斷是否由其他事務在使 用undo段中表的上一個事務之前的版本信息,決定是否可以清理undo log的日誌空間。

  • 5、對應的物理文件

    • MySQL5.6之前,undo表空間位於共享表空間的回滾段中,共享表空間的默認的名稱是ibdata,位於數據文件目錄中。

      MySQL5.6之後,undo表空間可以配置成獨立的文件,但是提前需要在配置文件中配置,完成數據庫初始化後生效且不可改變undo log文件的個數

      如果初始化數據庫之前沒有進行相關配置,那麼就無法配置成獨立的表空間了。

      關於MySQL5.7之後的獨立undo 表空間配置參數如下:

      innodb_undo_directory = /data/undospace/ –undo獨立表空間的存放目錄

      innodb_undo_logs = 128 –回滾段爲128KB

      innodb_undo_tablespaces = 4 –指定有4個undo log文件

      如果undo使用的共享表空間,這個共享表空間中又不僅僅是存儲了undo的信息,共享表空間的默認爲與MySQL的數據目錄下面,其屬性由參數innodb_data_file_path配置。

  • 6、其他

    • undo是在事務開始之前保存的被修改數據的一個版本,產生undo日誌的時候,同樣會伴隨類似於保護事務持久化機制的redolog的產生。

      默認情況下undo文件是保持在共享表空間的,也即ibdatafile文件中,當數據庫中發生一些大的事務性操作的時候,要生成大量的undo信息,全部保存在共享表空間中的。

      因此共享表空間可能會變的很大,默認情況下,也就是undo 日誌使用共享表空間的時候,被“撐大”的共享表空間是不會也不能自動收縮的。

      因此,mysql5.7之後的“獨立undo 表空間”的配置就顯得很有必要了。

2、3 二進制日誌(binlog)

  • 1、作用

    • 用於複製,在主從複製中,從庫利用主庫上的binlog進行重播,實現主從同步;

    用於數據庫的基於時間點的還原;

  • 2、內容

    • 邏輯格式的日誌,可以簡單認爲就是執行過的事務中的sql語句。

      但又不完全是sql語句這麼簡單,而是包括了執行的sql語句(增刪改)反向的信息,

      也就意味着delete對應着delete本身和其反向的insert;update對應着update執行前後的版本的信息;insert對應着delete和insert本身的信息。

      在使用mysqlbinlog解析binlog之後一些都會真相大白。

      因此可以基於binlog做到類似於oracle的閃回功能,其實都是依賴於binlog中的日誌記錄。

  • 3、什麼時候產生

    • 事務提交的時候,一次性將事務中的sql語句(一個事物可能對應多個sql語句)按照一定的格式記錄到binlog中。

      這裏與redo log很明顯的差異就是redo log並不一定是在事務提交的時候刷新到磁盤,redo log是在事務開始之後就開始逐步寫入磁盤。

      因此對於事務的提交,即便是較大的事務,提交(commit)都是很快的,但是在開啓了bin_log的情況下,對於較大事務的提交,可能會變得比較慢一些。

      這是因爲binlog是在事務提交的時候一次性寫入的造成的,這些可以通過測試驗證。

  • 4、什麼時候釋放

    • binlog的默認是保持時間由參數expire_logs_days配置,也就是說對於非活動的日誌文件,在生成時間超過expire_logs_days配置的天數之後,會被自動刪除。
  • 5、對應的物理文件

    • 配置文件的路徑爲log_bin_basename,binlog日誌文件按照指定大小,當日志文件達到指定的最大的大小之後,進行滾動更新,生成新的日誌文件。

      對於每個binlog日誌文件,通過一個統一的index文件來組織。

  • 6、其他

    • 二進制日誌的作用之一是還原數據庫的,這與redo log很類似,很多人混淆過,但是兩者有本質的不同:

      • 作用不同:redo log是保證事務的持久性的,是事務層面的,binlog作爲還原的功能,是數據庫層面的(當然也可以精確到事務層面的),雖然都有還原的意思,但是其保護數據的層次是不一樣的。

      • 內容不同:redo log是物理日誌,是數據頁面的修改之後的物理記錄,binlog是邏輯日誌,可以簡單認爲記錄的就是sql語句

      • 另外,兩者日誌產生的時間,可以釋放的時間,在可釋放的情況下清理機制,都是完全不同的。

      • 恢復數據時候的效率,基於物理日誌的redo log恢復數據的效率要高於語句邏輯日誌的binlog

      • 關於事務提交時,redo log和binlog的寫入順序,爲了保證主從複製時候的主從一致(當然也包括使用binlog進行基於時間點還原的情況),是要嚴格一致的,

      • MySQL通過兩階段提交過程來完成事務的一致性的,也即redo log和binlog的一致性的,理論上是先寫redo log,再寫binlog,兩個日誌都提交成功(刷入磁盤),事務纔算真正的完成。

2、4 錯誤日誌(errorlog)

  • 在mysql數據庫中,錯誤日誌功能是默認開啓的。並且,錯誤日誌無法被禁止。默認情況下,錯誤日誌存儲在mysql數據庫的數據文件中。錯誤日誌文件通常的名稱爲hostname.err。其中,hostname表示服務器主機名。

    錯誤日誌信息可以自己進行配置的,錯誤日誌所記錄的信息是可以通過log-error和log-warnings來定義的,其中log-err是定義是否啓用錯誤日誌的功能和錯誤日誌的存儲位置,log-warnings是定義是否將警告信息也定義至錯誤日誌中。默認情況下錯誤日誌大概記錄以下幾個方面的信息:服務器啓動和關閉過程中的信息(未必是錯誤信息,如mysql如何啓動InnoDB的表空間文件的、如何初始化自己的存儲引擎的等等)、服務器運行過程中的錯誤信息、事件調度器運行一個事件時產生的信息、在從服務器上啓動服務器進程時產生的信息。

2、5慢查詢日誌(slow query log)

  • 慢查詢日誌是用來記錄執行時間超過指定時間的查詢語句。通過慢查詢日誌,可以查找出哪些查詢語句的執行效率很低,以便進行優化。一般建議開啓,它對服務器性能的影響微乎其微,但是可以記錄mysql服務器上執行了很長時間的查詢語句。可以幫助我們定位性能問題的。

  • 查看慢查詢日誌的定義:

    mysql> SHOW GLOBAL VARIABLES LIKE ‘%log%’;
    | slow_query_log | OFF #定義慢查詢日誌的
    | slow_query_log_file |/mydata/data/stu18-slow.log #輸出方式爲file(文件)時定義慢查詢日誌的位置

2、6一般查詢日誌(general log)

  • 默認情況下查詢日誌是關閉的。由於查詢日誌會記錄用戶的所有操作,其中還包含增刪查改等信息,在併發操作大的環境下會產生大量的信息從而導致不必要的磁盤IO,會影響mysql的性能的。如若不是爲了調試數據庫的目的建議不要開啓查詢日誌。

2、7中繼日誌(relay log)

  • relay log是複製過程中產生的日誌,很多方面都跟bin log差不多,區別是: relay log是從庫服務器I/O線程將主庫服務器的二進制日誌讀取過來記錄到從庫服務器本地文件,然後從庫的SQL線程會讀取relay-log日誌的內容並應用到從庫服務器上。

3、鎖

3、1MySQL鎖的基本介紹

鎖是計算機協調多個進程或線程併發訪問某一資源的機制。在數據庫中,除傳統的 計算資源(如CPU、RAM、I/O等)的爭用以外,數據也是一種供許多用戶共享的資源。如何保證數據併發訪問的一致性、有效性是所有數據庫必須解決的一 個問題,鎖衝突也是影響數據庫併發訪問性能的一個重要因素。從這個角度來說,鎖對數據庫而言顯得尤其重要,也更加複雜。

相對其他數據庫而言,MySQL的鎖機制比較簡單,其最 顯著的特點是不同的存儲引擎支持不同的鎖機制。比如,MyISAM和MEMORY存儲引擎採用的是表級鎖(table-level locking);InnoDB存儲引擎既支持行級鎖(row-level locking),也支持表級鎖,但默認情況下是採用行級鎖。

3、2 常見的3種鎖

  • 行級鎖 行級鎖是Mysql中鎖定粒度最細的一種鎖,表示只針對當前操作的行進行加鎖。行級鎖能大大減少數據庫操作的衝突。其加鎖粒度最小,但加鎖的開銷也最大。行級鎖分爲共享鎖 和 排他鎖。

    特點:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的概率最低,併發度也最高。

  • 表級鎖 表級鎖是MySQL中鎖定粒度最大的一種鎖,表示對當前操作的整張表加鎖,它實現簡單,資源消耗較少,被大部分MySQL引擎支持。最常使用的MYISAM與INNODB都支持表級鎖定。表級鎖定分爲表共享讀鎖(共享鎖)與表獨佔寫鎖(排他鎖)。

    特點:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發出鎖衝突的概率最高,併發度最低。

  • 頁級鎖 頁級鎖是MySQL中鎖定粒度介於行級鎖和表級鎖中間的一種鎖。表級鎖速度快,但衝突多,行級衝突少,但速度慢。所以取了折衷的頁級,一次鎖定相鄰的一組記錄。

    特點:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,併發度一般

從上述特點可見,很難籠統地說哪種鎖更好,只能就具體應用的特點來說哪種鎖更合適!僅從鎖的角度 來說:表級鎖更適合於以查詢爲主,只有少量按索引條件更新數據的應用,如Web應用;而行級鎖則更適合於有大量按索引條件併發更新少量不同數據,同時又有 併發查詢的應用,如一些在線事務處理(OLTP)系統。

4、mvcc

4、1概念

英文全稱爲Multi-Version Concurrency Control,中文: 多版本併發控制,通過使用mvcc算法自動提供併發控制。mvcc可以維持一個數據的多個版本使讀寫操作沒有衝突

本質來看其實mvcc是一種樂觀鎖的實現!

前面也說過,事務的隔離性(事務的隔離性:併發事務之間互不影響),是由鎖+mvcc的方式實現的

4、2基於鎖的併發控制流程

  • 事務根據自己對數據項進行的操作類型申請相應的鎖(申請共享鎖,申請排他鎖)
  • 申請鎖的請求被髮送給鎖管理器。鎖管理器根據當前數據項是否已經有鎖以及申請的和持有的鎖是否衝突決定是否爲該請求授予鎖。
  • 若鎖被授予,則申請鎖的事務可以繼續執行;若被拒絕,則申請鎖的事務將進行等待,直到鎖被其他事務釋放。

mvcc說起來也是分存儲引擎的,因爲鎖是分存儲引擎的

InnoDB:通過爲每一行記錄添加兩個額外的隱藏的值來實現mvcc,這兩個值一個記錄這行 數據何時被創建,另外一個記錄這行數據何時過期(或者被刪除)。但是InnoDB並不存儲這些事件發生時的實際時間,相反它只存儲這些事件發生時的系統版 本號。這是一個隨着事務的創建而不斷增長的數字。每個事務在事務開始時會記錄它自己的系統版本號。每個查詢必須去檢查每行數據的版本號與事務的版本號是否相同。

4、3接下來以innoDB爲前提,舉例說明mvcc

1、版本鏈

我們先來理解一下版本鏈(鏈的概念就是地址)的概念。在InnoDB引擎表中,它的聚簇索引記錄中有兩個必要的隱藏列:

  • trx_id
    這個id用來存儲的每次對某條聚簇索引記錄進行修改的時候的事務id。

  • roll_pointer
    每次對哪條聚簇索引記錄有修改的時候,都會把老版本寫入undo日誌中。這個roll_pointer就是存了一個指針,它指向這條聚簇索引記錄的上一個版本的位置,通過它來獲得上一個版本的記錄信息。(注意插入操作的undo日誌沒有這個屬性,因爲它沒有老版本)

先插入一列:執行insert ,假設這個表只有兩個字段

id name trx_id roll_pointer
1 sjt 10 新紀錄沒有老版本

現在執行update,將sjt改爲sjt1

id name trx_id roll_pointer
1 sjt1 20 上一個版本的地址(即下面這條記錄的地址)
1 sjt 10 新紀錄沒有老版本

此時在undo日誌中就存在版本鏈

2、ReadView
ReadView中主要就是有個列表來存儲我們系統中當前活躍着的讀寫事務,也就是開始了還未提交的事務。通過這個列表來判斷記錄的某個版本是否對當前事務可見。

比如,當前活躍的事務的事務id(TRX_ID )爲[50,70](注意這裏的意義是集合,不是範圍

當你訪問事務id不在這個集合內的時候,是可以訪問的(比如,40,60等等),因爲事務都已經提交,當你訪問的事務id在這個集合內的時候([50,70]),你不能訪問,因爲事務還沒提交。(這個列表就是ReadView)

但需要注意,readView在不同的隔離級別也是不同的:
已提交讀和可重複讀的區別就在於它們生成ReadView的策略不同。

比如,在已提交讀隔離級別下:

在次update,但事務id爲30的這次事務沒有提交,所以此時的ReadView中只有[30]

id name trx_id roll_pointer
1 sjt2 30 上一個版本的地址(即下面這條記錄的地址)
1 sjt1 20 上一個版本的地址(即下面這條記錄的地址)
1 sjt 10 新紀錄沒有老版本

這時,另外一個事務B來訪問id爲1的這條記錄,它找到了事務id爲30的這條記錄,但是,事務id爲30的事務在ReadView中,所以不能訪問,事務B他沒拿到最新的記錄,所以,就會通過roll_pointer存儲的地址,找到trx_id爲20的記錄,此時檢查是否在ReadView中,不在,所以拿到了這條記錄

這時我們把事務id爲30的事務,提交,在此update一次(這次事務id爲40,也沒提交)

id name trx_id roll_pointer
1 sjt3 40 上一個版本的地址(即下面這條記錄的地址)
1 sjt2 30 上一個版本的地址(即下面這條記錄的地址)
1 sjt1 20 上一個版本的地址(即下面這條記錄的地址)
1 sjt 10 新紀錄沒有老版本

這個時候關鍵的地方來了

如果你是已提交讀隔離級別,這時候你會重新一個有ReadView,那你的活動事務列表中的值就變了,變成了[40]。

按照上的說法,你去版本鏈通過trx_id對比查找到合適的結果就是sjt2。

如果你是可重複讀隔離級別,這時候你的ReadView還是第一次select時候生成的ReadView,也就是列表的值還是[30]。所以訪問的結果是sjt1。所以第二次訪問結果和第一次一樣,所以叫可重複讀!

也就是說已提交讀隔離級別下的事務在每次查詢的開始都會生成一個獨立的ReadView,而可重複讀隔離級別則在第一次讀的時候生成一個ReadView,之後的讀都複用之前的ReadView。

5、存儲引擎

5、1概述

數據庫存儲引擎是數據庫底層軟件組織,數據庫管理系統(DBMS)使用數據引擎進行創建、查詢、更新和刪除數據。不同的存儲引擎提供不同的存儲機制、索引技巧、鎖定水平等功能,使用不同的存儲引擎,還可以 獲得特定的功能。現在許多不同的數據庫管理系統都支持多種不同的數據引擎。數據庫的核心就是存儲引擎,MySQL默認的存儲引擎是InoDB

我們常見(常用)的其實就前兩種,需要注意的是:存儲引擎是表級別的,也就是說不同的表可以有不同的存儲引擎

5、2InnoDB存儲引擎

InnoDB是事務型數據庫的首選引擎,支持事務安全表(ACID),支持行鎖定和外鍵,InnoDB是默認的MySQL引擎。

InnoDB主要特點:

  • 1、InnoDB給MySQL提供了具有提交、回滾和崩潰恢復能力的事物安全(ACID兼容)存儲引擎。InnoDB鎖定在行級並且也在SELECT語句中提供一個類似Oracle的非鎖定讀。這些功能增加了多用戶部署和性能。在SQL查詢中,可以自由地將InnoDB類型的表和其他MySQL的表類型混合起來,甚至在同一個查詢中也可以混合

  • 2、InnoDB是爲處理巨大數據量的最大性能設計。它的CPU效率可能是任何其他基於磁盤的關係型數據庫引擎鎖不能匹敵的

  • 3、InnoDB存儲引擎完全與MySQL服務器整合,InnoDB存儲引擎爲在主內存中緩存數據和索引而維持它自己的緩衝池。InnoDB將它的表和索引在一個邏輯表空間中,表空間可以包含數個文件(或原始磁盤文件)。這與MyISAM表不同,比如在MyISAM表中每個表被存放在分離的文件中。InnoDB表可以是任何尺寸,即使在文件尺寸被限制爲2GB的操作系統上

  • 4、InnoDB支持外鍵完整性約束,存儲表中的數據時,每張表的存儲都按主鍵順序存放,如果沒有顯示在表定義時指定主鍵,InnoDB會爲每一行生成一個6字節的ROWID,並以此作爲主鍵

  • 5、InnoDB被用在衆多需要高性能的大型數據庫站點上

InnoDB不創建目錄,使用InnoDB時,MySQL將在MySQL數據目錄下創建一個名爲ibdata1的10MB大小的自動擴展數據文件,以及兩個名爲ib_logfile0和ib_logfile1的5MB大小的日誌文件

使用innoDB的時候:會創建下面的兩個文件
在這裏插入圖片描述frm文件存儲表結構,ibd文件存儲索引和數據(聚集索引)

5、3MyISAM存儲引擎

MyISAM基於ISAM存儲引擎,並對其進行擴展。它是在Web、數據倉儲和其他應用環境下最常使用的存儲引擎之一。MyISAM擁有較高的插入、查詢速度,但不支持事物。

MyISAM主要特性有:

  • 1、大文件(達到63位文件長度)在支持大文件的文件系統和操作系統上被支持

  • 2、當把刪除和更新及插入操作混合使用的時候,動態尺寸的行產生更少碎片。這要通過合併相鄰被刪除的塊,以及若下一個塊被刪除,就擴展到下一塊自動完成

  • 3、每個MyISAM表最大索引數是64,這可以通過重新編譯來改變。每個索引最大的列數是16

  • 4、最大的鍵長度是1000字節,這也可以通過編譯來改變,對於鍵長度超過250字節的情況,一個超過1024字節的鍵將被用上

  • 5、BLOB和TEXT列可以被索引

  • 6、NULL被允許在索引的列中,這個值佔每個鍵的0~1個字節

  • 7、所有數字鍵值以高字節優先被存儲以允許一個更高的索引壓

  • 8、每個MyISAM類型的表都有一個AUTO_INCREMENT的內部列,當INSERT和UPDATE操作的時候該列被更新,同時AUTO_INCREMENT列將被刷新。所以說,MyISAM類型表的AUTO_INCREMENT列更新比InnoDB類型的AUTO_INCREMENT更快

  • 9、可以把數據文件和索引文件放在不同目錄

  • 10、每個字符列可以有不同的字符集

  • 11、有VARCHAR的表可以固定或動態記錄長度

  • 12、VARCHAR和CHAR列可以多達64KB

使用MyISAM引擎創建數據庫,將產生3個文件。文件的名字以表名字開始,擴展名之處文件類型:frm文件存儲表定義、數據文件的擴展名爲.MYD(MYData)、索引文件的擴展名時.MYI(MYIndex)
在這裏插入圖片描述

5、4MEMORY存儲引擎

MEMORY存儲引擎將表中的數據存儲到內存中,未查詢和引用其他表數據提供快速訪問。
MEMORY主要特性有:

  • 1、MEMORY表的每個表可以有多達32個索引,每個索引16列,以及500字節的最大鍵長度

  • 2、MEMORY存儲引擎執行HASH和BTREE縮影

  • 3、可以在一個MEMORY表中有非唯一鍵值

  • 4、MEMORY表使用一個固定的記錄長度格式

  • 5、MEMORY不支持BLOB或TEXT列

  • 6、MEMORY支持AUTO_INCREMENT列和對可包含NULL值的列的索引

  • 7、MEMORY表在所由客戶端之間共享(就像其他任何非TEMPORARY表)

  • 8、MEMORY表內存被存儲在內存中,內存是MEMORY表和服務器在查詢處理時的空閒中,創建的內部表共享

  • 9、當不再需要MEMORY表的內容時,要釋放被MEMORY表使用的內存,應該執行DELETE FROM或TRUNCATE TABLE,或者刪除整個表(使用DROP TABLE)

5、5MERGE存儲引擎

Merge存儲引擎是一組MyISAM表的組合,這些MyISAM表必須結構完全相同,merge表本身並沒有數據,對merge類型的表可以進行查詢,更新,刪除操作,這些操作實際上是對內部的MyISAM表進行的。
在這裏插入圖片描述

6、分庫分表

6、1分庫分表出現的背景

由於千萬級別,甚至上億的數據量導致單表單庫操作壓力過大,執行速度過慢…

簡單來講,分庫分表只是一種優化策略,不是什麼技術。

不論分庫還是分表,我們的核心思想就是,數據切分

  • 數據切分(Sharding),簡單的來說,就是通過某種特定的條件,將存放在同一個數據庫中的數據拆分存放到多個數據庫(主機)中,從而達到分散單臺機器負載的情況,即分庫分表。根據數據切分規則的不同,主要有兩種模式,
    • 垂直切分(縱向切分),是對不同的表(或者Schema)進行切分,存儲到不同的數據庫(主機)之上。
    • 水平切分(橫向切分),是對同一個表中的數據進行切分,存儲到不同的數據庫(主機)之上。規則是根據表中數據的邏輯關係,按照某種條件拆分。

接下來分別看這兩種模式

6、2垂直切分

垂直切分,強調的是業務的拆分。一個數據庫由多個表構成,每個表對應不同的業務,那麼我們可以指按照業務的不同將表進行分類,並將其分佈到不同的數據庫上,這樣就將數據分攤到了不同的庫上面,做到專庫專用。

舉個例子,原數據庫中有商品表、交易表、訂單表,我們可以按照業務的不同進行垂直切分,把商品表、交易表、訂單表分別拆分到商品庫、交易庫、訂單庫中去。

垂直拆分的優點:

  • 拆分規則明確,拆分後業務清晰;
  • 系統之間進行整合或擴展變的容易;
  • 數據維護變的容易;
  • 按照成本、應用的等級、應用的類型等將表放到不同的機器上,便於管理。

垂直拆分的缺點:

  • 部分業務表無法關聯(Join),只能通過接口方式解決,提高了系統的複雜度;
  • 受每種業務的不同限制,存在單庫性能瓶頸,不易進行數據擴展和提升性能;
  • 分佈式事務處理複雜。

6、3水平切分(重點)

水平切分,強調的是技術層面的拆分。她是將其按照一定的邏輯規則將一個表中的數據分散到多個庫中,在每個表中包含一部分數據,所有表加起來就是全量的數據。簡單來說,我們可以將對數據的水平切分理解爲按照數據行進行切分,就是將表中的某些行切分到一個數據庫表中,而將其他行切分到其他數據庫表中。

比如,原數據庫有一張交易記錄表,數據量非常大,其中表中有個地區字段,經過深入考證符合水平拆分的條件。我們就按照這個字段進行水平拆分,按不同的地區(北京、上海、江蘇、浙江、廣東等)拆分成10個庫。

高峯時段同時有100萬次請求,如果是單庫,數據庫就會承受100萬次的請求壓力,拆分成100個表分別放入10個庫中,每個表進行1萬次請求,則每個數據庫會承受10萬次的請求壓力,這樣壓力就減少了很多,並且是成倍減少的。

水平拆分的優點:

  • 拆分規則抽象好,join 操作基本可以數據庫做;
  • 不存在單庫大數據,高併發的性能瓶頸;
  • 應用端改造較少;
  • 提高了系統的穩定性跟負載能力。

水平拆分的缺點:

  • 拆分規則不好抽象;
  • 分片事務一致性難以解決;
  • 數據多次擴展難度大;
  • 跨庫 join 性能較差。

6、4數據切分導致的一些問題

上面我們也講了兩種數據切分方式的優點和缺點,但是他們有些共同的缺點,

  • 分佈式事務的問題;

  • 跨節點 Join 的問題;跨節點合併排序分頁的問題;

  • 多數據源管理問題。

  • 一般來說,業務上存在着複雜 join 的場景是很難切分的,往往業務獨立的易於切分。如何切分,我們遵循如下原則,

  • 能不切分儘量不要切分;

  • 如果要切分一定要選擇合適的切分規則,提前規劃好;

  • 數據切分儘量通過數據冗餘或表分組來降低跨庫 Join 的可能;

  • 由於數據庫中間件對數據 Join 實現的優劣難以把握,而且實現高性能難度極大,業務讀取儘量少使用多表 Join。

6、5分庫分表之後,數據源的管理是系統實現的關鍵。

系統應用層面
系統應用代碼層面,目前主要有兩種思路,

  • 客戶端模式
    也就是在每個應用程序模塊中配置管理自己需要的一個(或者多個)數據源,直接訪問各個數據庫,在模塊內完成數據的整合。比如可以依賴spring註解實現。

    中間代理模式,統一管理所有的數據源,後端數據庫集羣對前端應用程序透明。

    考慮到系統的複雜性和擴展性,建議第二種中間代理模式。雖然短期內需要付出的成本可能會相對更大一些,但是對整個系統的擴展性來說,是非常實用的。

  • 中間件層面
    上面的系統層面,需要的代碼實現比較複雜,中間件是在數據集羣前面加一層代理,比如Cobar、Mycat等數據庫中間件。實用數據庫中間件,對代碼層面的實現是很大的解放。

7、主從複製,讀寫分離

7、1概述

爲什麼需要主從複製,讀寫分離這種策略呢?

原因是:隨着數據量的增長,到達瓶頸之後,數據操作效率會變得很低,甚至不可用,所以我們要將讀/寫分離開,以此來緩解單庫的壓力,雖然讀寫分離,但是主從庫的數據得是同步的,否則讀寫分離,就沒有了意義!
在這裏插入圖片描述
仔細觀察上圖可以發現,主從庫用的日誌是不同的,主庫用的是專門用來保存修改數據庫表的所有動作的日誌,即bin log,從庫用的是中繼日誌。

在主庫的數據發生變化之後,底層的日誌系統運作,(之前已經介紹過日誌系統),來使主庫的數據變化,同樣的發生在從庫裏。

這樣讀寫分離得以運行,從而達到我們減輕單庫壓力的目的。

7、2主從複製的結果?

複製的結果是集羣(Cluster)中的所有數據庫服務器得到的數據理論上都是一樣的,都是同一份數據,只是有多個copy。MySQL默認內建的複製策略是異步的,基於不同的配置,Slave不一定要一直和Master保持連接不斷的複製或等待複製,我們可以指定複製所有的數據庫,一部分數據庫,甚至是某個數據庫的某部分的表。

7、3複製的幾種方式(策略)?

  • 同步策略:Master要等待所有Slave應答之後纔會提交(MySql對DB操作的提交通常是先對操作事件進行二進制日誌文件寫入然後再進行提交)。
  • 半同步策略:Master等待至少一個Slave應答就可以提交。(由google爲MySQL引入的。)
  • 異步策略:Master不需要等待Slave應答就可以提交。(類似ajax請求,異步策略也是MySQL默認的複製策略)
  • 延遲策略:Slave要至少落後Master指定的時間。

7、4主從複製的好處?

  • 性能方面:MySQL複製是一種Scale-out方案,也即“水平擴展”,將原來的單點負載擴散到多臺Slave機器中去,從而提高總體的服務性能。在這種方式下,所有的寫操作,當然包括UPDATE操作,都要發生在Master服務器上。讀操作發生在一臺或者多臺Slave機器上。這種模型可以在一定程度上提高總體的服務性能,Master服務器專注於寫和更新操作,Slave服務器專注於讀操作,我們同時可以通過增加Slave服務器的數量來提高讀服務的性能。——實現“讀”與“寫”分離
  • 故障恢復:同時存在多臺Slave提供讀操作服務,如果有一臺Slave掛掉之後我們還可以從其他Slave讀取,如果配置了主從切換的話,當Master掛掉之後我們還可以選擇一臺Slave作爲Master繼續提供寫服務,這大大增加了應用的可靠性。
  • 數據分析:實時數據可以存儲在Master,而數據分析可以從Slave讀取,這樣不會影響Master的性能。

7、5如何實現主從複製的?

mysql主從複製需要三個線程,master(binlog dump thread)、slave(I/O thread 、SQL thread)。

  • master
    binlog dump線程:當主庫中有數據更新時,那麼主庫就會根據按照設置的binlog格式,將此次更新的事件類型寫入到主庫的binlog文件中,此時主庫會創建log dump線程通知slave有數據更新,當I/O線程請求日誌內容時,會將此時的binlog名稱和當前更新的位置同時傳給slave的I/O線程。
    slave
  • I/O線程:該線程會連接到master,向log dump線程請求一份指定binlog文件位置的副本,並將請求回來的binlog存到本地的relay log中,relay log和binlog日誌一樣也是記錄了數據更新的事件,它也是按照遞增後綴名的方式,產生多個relay log( host_name-relay-bin.000001)文件,slave會使用一個index文件( host_name-relay-bin.index)來追蹤當前正在使用的relay log文件。
  • SQL線程:該線程檢測到relay log有更新後,會讀取並在本地做redo操作,將發生在主庫的事件在本地重新執行一遍,來保證主從數據同步。此外,如果一個relay log文件中的全部事件都執行完畢,那麼SQL線程會自動將該relay log 文件刪除掉。

8、索引

8、1 索引是什麼?

索引說到底,它就是幫助MySQL高效獲取數據的排好序的數據結構,就像是一本書的目錄一般

8、2 索引有哪幾種類型?

  • 主鍵索引: 數據列不允許重複,不允許爲NULL,一個表只能有一個主鍵。

  • 唯一索引: 數據列不允許重複,允許爲NULL值,一個表允許多個列創建唯一索引。

    可以通過 ALTER TABLE table_name ADD UNIQUE (column); 創建唯一索引

    可以通過 ALTER TABLE table_name ADD UNIQUE (column1,column2); 創建唯一組合索引

  • 普通索引: 基本的索引類型,沒有唯一性的限制,允許爲NULL值。

    可以通過ALTER TABLE table_name ADD INDEX index_name (column);創建普通索引

    可以通過ALTER TABLE table_name ADD INDEX index_name(column1, column2, column3);創建組合索引

  • 全文索引: 是目前搜索引擎使用的一種關鍵技術。

    可以通過ALTER TABLE table_name ADD FULLTEXT (column);創建全文索引

8、3 索引在哪裏用?

說簡單一點:where,order by,join這些關鍵字後面的字段,一般需要使用來進行SQL優化

8、4 索引的數據結構的演變:

  • 二叉樹:這種數據結構,索引數據單邊增長的時候,查找不方便
    在這裏插入圖片描述
    二叉樹的深度會越來越深,查找的代價也會越來越大
  • 紅黑樹(自平衡二叉樹):這種數據結構的缺點呢是:當索引數據量過大的時候,樹的高度會過高
    在這裏插入圖片描述
  • Hash表:hash表做索引的時候,只需做一次哈希運算就能找到對應的那一行數據,但是,當時的搜索條件是範圍查詢(大於之類的)就不能用了。而我們實際的業務中很多也都是範圍查詢,等值查詢很少。
  • B-Tree:一個節點存放很多個節點,(同樣還是左邊小,右邊大)b樹解決了二叉樹和紅黑樹的弊端,但還是不能範圍查找
    • b樹的葉子節點具有相同的深度
    • b樹的葉子節點指針爲空
    • 節點中的數據索引從左到右遞增排列
      在這裏插入圖片描述
  • B+樹:mysql官方默認規定一行總共存儲節點是16k,當然可以設置。假設如果是3層的B+樹,存滿可以存儲2000W+行數據(正常字段存儲)
    • 非葉子節點不存儲數據,只存儲索引, 這樣就可以放更多的索引
    • 葉子節點不存儲指針
    • 順序訪問指針,提高區間訪問能力
      在這裏插入圖片描述
      b+樹比b樹的一個進步就是,將數據(data)全部存儲在葉子節點,這樣非葉子節點就可以存儲更多的節點,這樣就可以存儲更多的data,至於範圍查找,B+樹的葉子節點之間是有雙向指針的。
      圖中的空白之處存的就是下一個節點的位置。

數據結構在線動態查看網站:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

9、MySQL性能優化

9、1 SQL的性能優化之索引優化

索引優化使用的是最左匹配原則

優化過程的調試,使用explain關鍵字即可

EXPLAIN關鍵字的使用:

  • EXPLAIN不會告訴你關於觸發器、存儲過程的信息或用戶自定義函數對查詢的影響情況
  • EXPLAIN不考慮各種Cache
  • EXPLAIN不能顯示MySQL在執行查詢時所作的優化工作
  • 部分統計信息是估算的,並非精確值
  • EXPALIN只能解釋SELECT操作,其他操作要重寫爲SELECT後查看執行計劃。

例如:
在這裏插入圖片描述
字段含義如下

  • id:選擇標識符
  • select_type:表示查詢的類型。
  • table:輸出結果集的表
  • partitions:匹配的分區
  • type:表示表的連接類型
  • possible_keys:表示查詢時,可能使用的索引
  • key:表示實際使用的索引
  • key_len:索引字段的長度
  • ref:列與索引的比較
  • rows:掃描出的行數(估算的行數)
  • filtered:按表條件過濾的行百分比
  • Extra:執行情況的描述和說明

下面的例子可以很好的理解最左匹配原則
在這裏插入圖片描述
注意:第四條雖然用到了索引,但只用到了name這個索引,這就是單表索引優化的原則只一:在聯合索引中 範圍以後的索引會導致索引失效

1、只要列中包含有NULL值都將不會被包含在索引中

2、複合索引中只要有一列含有NULL值,那麼這一列對於此複合索引就是無效的,所以我們在數據庫設計時儘可能不要讓字段的默認值爲NULL。

MySQL整體的性能,初次之外,庫,表,字段,字段大小,等等一切的細節,都是保證MySQL性能的重要組成。SQL優化,是後事

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