回顧篇-mysql索引-讀書筆記

  •     事務日誌

事務日誌可以幫助提高事務的效率。使用事務日誌,存儲引擎在修改表的數據時只需要修改其內存拷貝,再把該修改行爲記錄到持久在硬盤上的事務日誌中,而不用每次都將修改的數據本身持久到磁盤。事務日誌採用的是追加的方式,因此寫日誌的操作是磁盤上一小塊區域內的順序I/O,而不像隨機I/O需要在磁盤的多個地方移動磁頭,所以採用事務日誌的方式相對來說要快得多。事務日誌持久以後,內存中被修改的數據在後臺可以慢慢地刷回到磁盤。目前大多數存儲引擎都是這樣實現的,我們通常稱之爲預寫式日誌(Write-Ahead Logging),修改數據需要寫兩次磁盤。 如果數據的修改已經記錄到事務日誌並持久化,但數據本身還沒有寫回磁盤,此時系統崩潰,存儲引擎在重啓時能夠自動恢復這部分修改的數據。具體的恢復方式則視存儲引擎而定。

  •     多版本併發控制

MySQL的大多數事務型存儲引擎實現的都不是簡單的行級鎖。基於提升併發性能的考慮,它們一般都同時實現了多版本併發控制(MVCC)。不僅是MySQL,包括Oracle、PostgreSQL等其他數據庫系統也都實現了MVCC,但各自的實現機制不盡相同,因爲MVCC沒有一個統一的實現標準。實現了非阻塞的讀操作,寫操作也只鎖定必要的行。
 

  • MVCC的實現

是通過保存數據在某個時間點的快照來實現的。也就是說,不管需要執行多長時間,每個事務看到的數據都是一致的。根據事務開始的時間不同,每個事務對同一張表,同一時刻看到的數據可能是不一樣的。

    InnoDB的MVCC是通過在每行記錄後面保存兩個隱藏的列來實現的。這兩個列,一個保存了行的創建時間,一個保存行的過期時間(或刪除時間)。當然存儲的並不是實際的時間值,而是系統版本號(system version number)。每開始一個新的事務,系統版本號都會自動遞增。事務開始時刻的系統版本號會作爲事務的版本號,用來和查詢到的每行記錄的版本號進行比較。

    MVCC只在REPEATABLE READ和READ COMMITTED兩個隔離級別下工作。其他兩個隔離級別都和MVCC不兼容,因爲READ UNCOMMITTED總是讀取最新的數據行,而不是符合當前事務版本的數據行。而SERIALIZABLE則會對所有讀取的行都加鎖。
    InnoDB採用MVCC來支持高併發,並且實現了四個標準的隔離級別。其默認級別是REPEATABLE READ(可重複讀),並且通過間隙鎖(next-key locking)策略防止幻讀的出現。間隙鎖使得InnoDB不僅僅鎖定查詢涉及的行,還會對索引中的間隙進行鎖定,以防止幻影行的插入。

  • InnoDB聚簇索引

    InnoDB表是基於聚簇索引建立的,我們會在後面的章節詳細討論聚簇索引。InnoDB的索引結構和MySQL的其他存儲引擎有很大的不同,聚簇索引對主鍵查詢有很高的性能。不過它的二級索引(secondary index,非主鍵索引)中必須包含主鍵列,所以如果主鍵列很大的話,其他的所有索引都會很大。
    InnoDB內部做了很多優化,包括從磁盤讀取數據時採用的可預測性預讀,能夠自動在內存中創建hash索引以加速讀操作的自適應

     存儲引擎需要找到二級索引的葉子節點獲得對應的主鍵值,然後根據這個值去聚簇索引中查找到對應的行。這裏做了重複的工作:兩次B-Tree查找而不是一次。對於InnoDB,自適應哈希索引能夠減少這樣的重複工作。

    InnoDB二級索引的葉子節點中存儲的不是“行指針”,而是主鍵值,並以此作爲指向行的“指針”。這樣的策略減少了當出現行移動或者數據頁分裂時二級索引的維護工作。使用主鍵值當作指針會讓二級索引佔用更多的空間,換來的好處是,InnoDB在移動行時無須更新二級索引中的這個“指針”。

    從性能的角度考慮,使用UUID來作爲聚簇索引則會很糟糕:它使得聚簇索引的插入變得完全隨機,這是最壞的情況,使得數據沒有任何聚集特性。因爲主鍵的值是順序的,所以InnoDB把每一條記錄都存儲在上一條記錄的後面。當達到頁的最大填充因子時(InnoDB默認的最大填充因子是頁大小的15  /16,留出部分空間用於以後修改),下一條記錄就會寫入新的頁中。一旦數據按照這種順序的方式加載,主鍵頁就會近似於被順序的記錄填滿,這也正是所期望的結果(然而,二級索引頁可能是不一樣的)。

中移除,或者是還沒有被加載到緩存中,InnoDB在插入之前不得不先找到並從磁盤讀取目標頁到內存中。這將導致大量的隨機I/O。 因爲寫入是亂序的,InnoDB不得不頻繁地做頁分裂操作,以便爲新的行分配空間。頁分裂會導致移動大量數據,一次插入最少需要修改三個頁而不是一個頁。 由於頻繁的頁分裂,頁會變得稀疏並被不規則地填充,所以最終數據會有碎片。
 

  • MyISAM存儲引擎

    MyISAM提供了大量的特性,包括全文索引、壓縮、空間函數(GIS)等,但MyISAM不支持事務和行級鎖,而且有一個毫無疑問的缺陷就是崩潰後無法安全恢復。正是由於MyISAM引擎的緣故,即使MySQL支持事務已經很長時間了,在很多人的概念中MySQL還是非事務型的數據庫。儘管MyISAM引擎不支持事務、不支持崩潰後的安全恢復,但它絕不是一無是處的。對於只讀的數據,或者表比較小、可以忍受修復(repair)操作,則依然可以繼續使用MyISAM(但請不要默認使用MyISAM,而是應當默認使用InnoDB)。

  • 索引的類型

    B-Tree索引

    哈希索引,在MySQL中,只有Memory引擎顯式支持哈希索引。    哈希索引只包含哈希值和行指針,而不存儲字段值,所以不能使用索引中的值來避免讀取行。不過,訪問內存中的行的速度很快,所以大部分情況下這一點對性能的影響並不明顯。 哈希索引數據並不是按照索引值順序存儲的,所以也就無法用於排序。 哈希索引也不支持部分索引列匹配查找,因爲哈希索引始終是使用索引列的全部內容來計算哈希值的。例如,在數據列(A,B)上建立哈希索引,如果查詢只有數據列A,則無法使用該索引。 哈希索引只支持等值比較查詢,包括=、IN()、<=>(注意<>和<=>是不同的操作)。也不支持任何範圍查詢,例如WHERE price>100。 訪問哈希索引的數據非常快,除非有很多哈希衝突(不同的索引列值卻有相同的哈希值)。當出現哈希衝突的時候,存儲引擎必須遍歷鏈表中所有的行指針,逐行進行比較,直到找到所有符合條件的行。 如果哈希衝突很多的話,一些索引維護操作的代價也會很高。例如,如果在某個選擇性很低(哈希衝突很多)的列上建立哈希索引,那麼當從表中刪除一行時,存儲引擎需要遍歷對應哈希值的鏈表中的每一行,找到並刪除對應行的引用,衝突越多,代價越大。

空間數據索引(R-Tree)

全文索引,是一種特殊類型的索引,它查找的是文本中的關鍵詞,而不是直接比較索引中的值。全文搜索和其他幾類索引的匹配方式完全不一樣。它有許多需要注意的細節,如停用詞、詞幹和複數、布爾搜索等。全文索引更類似於搜索引擎做的事情,而不是簡單的WHERE條件匹配。在相同的列上同時創建全文索引和基於值的B-Tree索引不會有衝突,全文索引適用於MATCH AGAINST操作,而不是普通的WHERE條件操作。

  • 排序操作

    MySQL有兩種方式可以生成有序的結果:通過排序操作;或者按索引順序掃描(13);如果EXPLAIN出來的type列的值爲“index”,則說明MySQL使用了索引掃描來做排序

  • 覆蓋索引

    如果索引的葉子節點中已經包含要查詢的數據,那麼還有什麼必要再回表查詢呢?如果一個索引包含(或者說覆蓋)所有需要查詢的字段的值,我們就稱之爲“覆蓋索引”
索引條目通常遠小於數據行大小,所以如果    只需要讀取索引,那MySQL就會極大地減少數據訪問量。這對緩存的負載非常重要,因爲這種情況下響應時間大部分花費在數據拷貝上。覆蓋索引對於I/O密集型的應用也有幫助,因爲索引比數據更小,更容易全部放入內存中(這對於MyISAM尤其正確,因爲MyISAM能壓縮索引以變得更小)。

 不是所有類型的索引都可以成爲覆蓋索引。覆蓋索引必須要存儲索引列的值,而哈希索引、空間索引和全文索引等都不存儲索引列的值,所以MySQL只能使用B-Tree索引做覆蓋索引。

  • 使用索引掃描來做排序

    掃描索引本身是很快的,因爲只需要從一條索引記錄移動到緊接着的下一條記錄。但如果索引不能覆蓋查詢所需的全部列,那就不得不每掃描一條索引記錄就都回表查詢一次對應的行。這基本上都是隨機I/O,因此按索引順序讀取數據的速度通常要比順序地全表掃描慢,尤其是在I/O密集型的工作負載時。
壓縮(前綴壓縮)索引    MyISAM使用前綴壓縮來減少索引的大小,從而讓更多的索引可以放入內存中,這在某些情況下能極大地提高性能。默認只壓縮字 符串,但通過參數設置也可以對整數做壓縮。MyISAM壓縮每個索引塊的方法是,先完全保存索引塊中的第一個值,然後將其他值和第一個值進行比較得到相同前綴的字節數和剩餘的不同後綴部分,把這部分存儲起來即可。例如,索引塊中的第一個值是“perform”,第二個值是“performance”,那麼第二個值的前綴壓縮後存儲的是類似“7,ance”這樣的形式。MyISAM對行指針也採用類似的前綴壓縮方式。
壓縮塊使用更少的空間,代價是某些操作可能更慢。因爲每個值的壓縮前綴都依賴前面的值,所以MyISAM查找時無法在索引塊使用二分查找而只能從頭開始掃描。正序的掃描速    度還不錯,但是如果是倒序掃描——例如ORDER BY DESC——就不是很好了。所有在塊中查找某一行的操作平均都需要掃描半個索引塊。

  •     索引和鎖

 InnoDB只有在訪問行的時候纔會對其加鎖,而索引能夠減少InnoDB訪問的行數,

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