MySQL學習筆記1.0

1.兩種日誌(binlog 和 redo log)

1.這兩種日誌有以下三點不同。redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 層實現的,所有引擎都可以使用。
2.redo log 是物理日誌,記錄的是“在某個數據頁上做了什麼修改”;binlog 是邏輯日誌,記錄的是這個語句的原始邏輯。
3.redo log 是循環寫的,空間固定會用完;binlog 是可以追加寫入的。“追加寫”是指 binlog 文件寫到一定大小後會切換到下一個,並不會覆蓋以前的日誌。

爲了保證數據庫的一致性,必須要保證2份日誌一致,因此使用的兩階段式提交。

2.事務隔離

    SQL 標準的事務隔離級別包括:讀未提交(read uncommitted)、讀提交(read committed)、可重複讀(repeatable read)和串行化(serializable )。

  • 讀未提交是指,一個事務還沒提交時,它做的變更就能被別的事務看到。
  • 讀提交是指,一個事務提交之後,它做的變更纔會被其他事務看到。
  • 可重複讀是指,一個事務執行過程中看到的數據,總是跟這個事務在啓動時看到的數據是一致的。當然在可重複讀隔離級別下,未提交變更對其他事務也是不可見的。
  • 串行化,顧名思義是對於同一行記錄,“寫”會加“寫鎖”,“讀”會加“讀鎖”。當出現讀寫鎖衝突的時候,後訪問的事務必須等前一個事務執行完成,才能繼續執行。

3.索引

    在 InnoDB 中,表都是根據主鍵順序以索引的形式存放的,這種存儲方式的表稱爲索引組織表。又因爲前面我們提到的,InnoDB 使用了 B+ 樹索引模型,所以數據都是存儲在 B+ 樹中的。
    根據葉子節點的內容,索引類型分爲主鍵索引和非主鍵索引。主鍵索引的葉子節點存的是整行數據。在 InnoDB 裏,主鍵索引也被稱爲聚簇索引(clustered index)。非主鍵索引的葉子節點內容是主鍵的值。在 InnoDB 裏,非主鍵索引也被稱爲二級索引(secondary index)。

覆蓋索引、最左前綴原則、索引下推

4.表級鎖

    MySQL 裏面表級別的鎖有兩種:一種是表鎖,一種是元數據鎖(meta data lock,MDL)。
    MDL 不需要顯式使用,在訪問一個表的時候會被自動加上。MDL 的作用是,保證讀寫的正確性在 MySQL 5.5 版本中引入了 MDL,當對一個表做增刪改查操作的時候,加 MDL 讀鎖;當要對錶做結構變更操作的時候,加 MDL 寫鎖。

  • 讀鎖之間不互斥,因此你可以有多個線程同時對一張表增刪改查。
  • 讀寫鎖之間、寫鎖之間是互斥的,用來保證變更表結構操作的安全性。因此,如果有兩個線程要同時給一個表加字段,其中一個要等另一個執行完才能開始執行。

5.普通索引和唯一索引

    普通索引和唯一索引應該怎麼選擇?
    其實,這兩類索引在查詢能力上是沒差別的,主要考慮的是對更新性能的影響。實際使用中,普通索引和 change buffer 的配合使用,對於數據量大的表的更新優化還是很明顯的。

6.索引選擇異常

索引選擇異常和處理:

    對於由於索引統計信息不準確導致的問題,可以用 analyze table 來解決。

    而對於其他優化器誤判的情況:
    1.採用 force index 強行選擇一個索引。
    2.考慮修改語句,引導 MySQL 使用我們期望的索引。
    3.在有些場景下,可以新建一個更合適的索引,來提供給優化器做選擇,或刪掉誤用的索引。

7.給字符串字段加索引

    1.使用前綴索引,定義好長度,就可以做到既節省空間,又不用額外增加太多的查詢成本。但使用前綴索引就無法使用覆蓋索引對查詢性能的優化,這也是在選擇是否使用前綴索引時需要考慮的一個因素。

    2.總結:

  • 直接創建完整索引,這樣可能比較佔用空間;
  • 創建前綴索引,節省空間,但會增加查詢掃描次數,並且不能使用覆蓋索引;
  • 倒序存儲,再創建前綴索引,用於繞過字符串本身前綴的區分度不夠的問題;
  • 創建 hash 字段索引,查詢性能穩定,有額外的存儲和計算消耗,跟第三種方式一樣,都不支持範圍掃描。

8.數據庫表的空間回收

    一個 InnoDB 表包含兩部分,即:表結構定義和數據。表結構定義佔用的空間很小,主要考慮表數據的空間回收。

    表數據既可以存在共享表空間裏,也可以是單獨的文件。這個行爲是由參數 innodb_file_per_table 控制的:
    這個參數設置爲 OFF 表示的是,表的數據放在系統共享表空間,也就是跟數據字典放在一起;
    這個參數設置爲 ON 表示的是,每個 InnoDB 表數據存儲在一個以 .ibd 爲後綴的文件中。
    從 MySQL 5.6.6 版本開始,它的默認值就是 ON 了。我建議你不論使用 MySQL 的哪個版本,都將這個值設置爲 ON。因爲,一個表單獨存儲爲一個文件更容易管理,而且在你不需要這個表的時候,通過 drop table 命令,系統就會直接刪除這個文件。而如果是放在共享表空間中,即使表刪掉了,空間也是不會回收的。
    如果要收縮一個表,只是 delete 掉表裏面不用的數據的話,表文件的大小是不會變的,還要通過 alter table 命令重建表,才能達到表文件變小的目的。

9.count()函數

    count(*)、count(主鍵 id) 和 count(1) 都表示返回滿足條件的結果集的總行數;而 count(字段),則表示返回滿足條件的數據行裏面,參數“字段”不爲 NULL 的總個數。

  • 對於 count(主鍵 id) 來說,InnoDB 引擎會遍歷整張表,把每一行的 id 值都取出來,返回給 server 層。server 層拿到 id 後,判斷是不可能爲空的,就按行累加。
  • 對於 count(1) 來說,InnoDB 引擎遍歷整張表,但不取值。server 層對於返回的每一行,放一個數字“1”進去,判斷是不可能爲空的,按行累加。單看這兩個用法的差別的話,count(1) 執行得要比 count(主鍵 id) 快。因爲從引擎返回 id 會涉及到解析數據行,以及拷貝字段值的操作。
  • 對於 count(字段) 來說:如果這個“字段”是定義爲 not null 的話,一行行地從記錄裏面讀出這個字段,判斷不能爲 null,按行累加;如果這個“字段”定義允許爲 null,那麼執行的時候,判斷到有可能是 null,還要把值取出來再判斷一下,不是 null 才累加。
  • 但是 count( * ) 是例外,並不會把全部字段取出來,而是專門做了優化,不取值。count ( * ) 肯定不是 null,按行累加。
        按照效率排序的話,count(字段)<count(主鍵 id)<count(1)≈count( * ),所以建議儘量使用 count( * )。

10.隨機查詢數據

    如果直接使用 order by rand(),這個語句需要 Using temporary 和 Using filesort,查詢的執行代價往往是比較大的。所以,在設計的時候你要儘量避開這種寫法。在實際應用的過程中,比較規範的用法就是:儘量將業務邏輯寫在業務代碼中,讓數據庫只做“讀寫數據”的事情。

11.函數操作

對索引字段做函數操作,可能會破壞索引值的有序性,因此優化器就決定放棄走樹搜索功能。同時,隱式類型轉換,隱式字符編碼轉換,也會要求在索引字段上做函數操作而導致了全索引掃描。

12.binlog 的三種格式

    一種是 statement,一種是 row。還有一種 mixed,其實它就是前兩種格式的混合。
    當 binlog_format=statement 時,binlog 裏面記錄的就是 SQL 語句的原文。
    當 binlog_format 使用 row 格式的時候,binlog 裏面記錄了真實修改行的數據。
    因爲有些 statement 格式的 binlog 可能會導致主備不一致,所以要使用 row 格式。但 row 格式的缺點是,很佔空間。比如你用一個 delete 語句刪掉 10 萬行數據,用 statement 的話就是一個 SQL 語句被記錄到 binlog 中,佔用幾十個字節的空間。但如果用 row 格式的 binlog,就要把這 10 萬條記錄都寫到 binlog 中。這樣做,不僅會佔用更大的空間,同時寫 binlog 也要耗費 IO 資源,影響執行速度。所以,MySQL 就取了個折中方案,也就是有了 mixed 格式的 binlog。mixed 格式的意思是,MySQL 自己會判斷這條 SQL 語句是否可能引起主備不一致,如果有可能,就用 row 格式,否則就用 statement 格式。也就是說,mixed 格式可以利用 statment 格式的優點,同時又避免了數據不一致的風險。

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