當前位置:首頁 » 服務存儲 » innodb二級索引存儲
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

innodb二級索引存儲

發布時間: 2022-08-04 23:25:22

A. mysql存儲方式MyISAM 和 InnoDB的區別

MYISAM 表是典型的數據與索引分離存儲,主鍵和二級索引沒有本質區別。比如在 MYISAM 表裡主鍵、唯一索引是一樣的,沒有本質區別。
INNODB 表本身是索引組織表,也就是說索引就是數據。下圖表T1的數據行以聚簇索引的方式展示,非葉子節點保存了主鍵的值,葉子節點保存了主鍵的值以及對應的數據行,並且每個頁有分別指向前後兩頁的指針。
INNODB 表不同於 MYISAM,INNODB 表有自己的數據頁管理,默認 16KB。MYISAM 表數據的管理依賴文件系統,比如文件系統一般默認 4KB,MYISAM的塊大小也是 4KB,MYISAM 表的沒有自己的一套崩潰恢復機制,全部依賴於文件系統。
INNODB 表這樣設計的優點有兩個:
1. 數據按照主鍵順序存儲。主鍵的順序也就是記錄行的物理順序,相比指向數據行指針的存放方式,避免了再次排序。我們知道,排序消耗最大。
2. 兩個葉子節點分別含有指向前後兩個節點的指針,這樣在插入新行或者進行頁分裂時,只需要移動對應的指針即可。
INNODB 二級索引的非葉子節點保存索引的欄位值,上圖索引為表 t1 的欄位 age。葉子節點含有索引欄位值和對應的主鍵值。
這樣做的優點是當出現數據行移動或者數據頁分裂時,避免二級索引不必要的維護工作。當數據需要更新的時候,二級索引不需要重建,只需要修改聚簇索引即可。
但是也有缺點:
1. 二級索引由於同時保存了主鍵值,體積會變大。特別是主鍵設計不合理的時候,比如用 UUID 做主鍵。
2. 對二級索引的檢索需要檢索兩次索引樹。第一次通過檢索二級索引葉子節點,找到過濾行對應的主鍵值;第二次通過這個主鍵的值去聚簇索引中查找對應的行。

B. 為什麼InnoDB表要建議用自增列做主鍵

InnoDB 被稱為索引組織型的存儲引擎。主鍵使用的 B-Tree 來存儲數據,即錶行。這意味著 InnoDB 必須使用主鍵。如果表沒有主鍵,InnoDB 會向表中添加一個隱藏的自動遞增的 6 位元組計數器,並使用該隱藏計數器作為主鍵。InnoDB 的隱藏主鍵存在一些問題。您應該始終在表上定義顯式主鍵,並通過主鍵值訪問所有 InnoDB 行。InnoDB 的二級索引也是一個B-Tree。搜索關鍵字由索引列組成,存儲的值是匹配行的主鍵。通過二級索引進行搜索通常會導致主鍵的隱式搜索。

C. innodb的索引數據結構定義在哪些文件中的

從 MySQL 5.7 開始,開發人員改變了 InnoDB 構建二級索引的方式,採用自下而上的方法,而不是早期版本中自上而下的方法了。在這篇文章中,我們將通過一個示例來說明如何構建 InnoDB 索引。最後,我將解釋如何通過為 innodb_fill_factor 設置更合適的值。

索引構建過程

在有數據的表上構建索引,InnoDB 中有以下幾個階段:1.讀取階段(從聚簇索引讀取並構建二級索引條目)2.合並排序階段3.插入階段(將排序記錄插入二級索引)在 5.6 版本之前,MySQL 通過一次插入一條記錄來構建二級索引。這是一種「自上而下」的方法。搜索插入位置從樹的根部(頂部)開始並達到葉頁(底部)。該記錄插入游標指向的葉頁上。在查找插入位置和進行業面拆分和合並方面開銷很大。從MySQL 5.7開始,添加索引期間的插入階段使用「排序索引構建」,也稱為「批量索引載入」。在這種方法中,索引是「自下而上」構建的。即葉頁(底部)首先構建,然後非葉級別直到根(頂部)。

示例

在這些情況下使用排序的索引構建:

  • ALTER TABLE t1 ADD INDEX(or CREATE INDEX)

  • ALTER TABLE t1 ADD FULLTEXT INDEX

  • ALTER TABLE t1 ADD COLUMN, ALGORITHM = INPLACE

  • OPIMIZE t1

  • 對於最後兩個用例,ALTER 會創建一個中間表。中間表索引(主要和次要)使用「排序索引構建」構建。

  • 演算法

  • 在 0 級別創建頁,還要為此頁創建一個游標

  • 使用 0 級別處的游標插入頁面,直到填滿

  • 頁面填滿後,創建一個兄弟頁(不要插入到兄弟頁)

  • 為當前的整頁創建節點指針(子頁中的最小鍵,子頁碼),並將節點指針插入上一級(父頁)

  • 在較高級別,檢查游標是否已定位。如果沒有,請為該級別創建父頁和游標

  • 在父頁插入節點指針

  • 如果父頁已填滿,請重復步驟 3, 4, 5, 6

  • 現在插入兄弟頁並使游標指向兄弟頁

  • 在所有插入的末尾,每個級別的游標指向最右邊的頁。提交所有游標(意味著提交修改頁面的迷你事務,釋放所有鎖存器)

  • 為簡單起見,上述演算法跳過了有關壓縮頁和 BLOB(外部存儲的 BLOB)處理的細節。

  • 通過自下而上的方式構建索引

    為簡單起見,假設子頁和非子頁中允許的 最大記錄數為 3

  • CREATE TABLE t1 (a INT PRIMARY KEY, b INT, c BLOB);

  • INSERT INTO t1 VALUES (1, 11, 'hello111');

  • INSERT INTO t1 VALUES (2, 22, 'hello222');

  • INSERT INTO t1 VALUES (3, 33, 'hello333');

  • INSERT INTO t1 VALUES (4, 44, 'hello444');

  • INSERT INTO t1 VALUES (5, 55, 'hello555');

  • INSERT INTO t1 VALUES (6, 66, 'hello666');

  • INSERT INTO t1 VALUES (7, 77, 'hello777');

  • INSERT INTO t1 VALUES (8, 88, 'hello888');

  • INSERT INTO t1 VALUES (9, 99, 'hello999');

  • INSERT INTO t1 VALUES (10, 1010, 'hello101010');

  • ALTER TABLE t1 ADD INDEX k1(b);

  • InnoDB 將主鍵欄位追加到二級索引。二級索引 k1 的記錄格式為(b, a)。在排序階段完成後,記錄為:

  • (11,1), (22,2), (33,3), (44,4), (55,5), (66,6), (77,7), (88,8), (99,9), (1010, 10)

  • 初始插入階段

  • 讓我們從記錄 (11,1) 開始。

  • 在 0 級別(葉級別)創建頁

  • 創建一個到頁的游標

  • 所有插入都將轉到此頁面,直到它填滿了

  • 箭頭顯示游標當前指向的位置。它目前位於第 5 頁,下一個插入將轉到此頁面。

  • 還有兩個空閑插槽,因此插入記錄 (22,2) 和 (33,3) 非常簡單

    對於下一條記錄 (44,4),頁碼 5 已滿(前面提到的假設最大記錄數為 3)。這就是步驟。

    頁填充時的索引構建

  • 創建一個兄弟頁,頁碼 6

  • 不要插入兄弟頁

  • 在游標處提交頁面,即迷你事務提交,釋放鎖存器等

  • 作為提交的一部分,創建節點指針並將其插入到 【當前級別 + 1】 的父頁面中(即在 1 級別)

  • 節點指針的格式 (子頁面中的最小鍵,子頁碼) 。第 5 頁的最小鍵是 (11,1) 。在父級別插入記錄 ((11,1),5)。

  • 1 級別的父頁尚不存在,MySQL 創建頁碼 7 和指向頁碼 7 的游標。

  • 將 ((11,1),5) 插入第 7 頁

  • 現在,返回到 0 級並創建從第 5 頁到第 6 頁的鏈接,反之亦然

  • 0 級別的游標現在指向兄弟頁,頁碼為 6

  • 將 (44,4) 插入第 6 頁

  • 下一個插入 - (55,5) 和 (66,6) - 很簡單,它們轉到第 6 頁。

  • 插入記錄 (77,7) 類似於 (44,4),除了父頁面 (頁面編號 7) 已經存在並且它有兩個以上記錄的空間。首先將節點指針 ((44,4),8) 插入第 7 頁,然後將 (77,7) 記錄到同級 8 頁中。

  • 插入記錄 (88,8) 和 (99,9) 很簡單,因為第 8 頁有兩個空閑插槽。

  • 下一個插入 (1010,10) 。將節點指針 ((77,7),8) 插入 1級別的父頁(頁碼 7)。

    MySQL 在 0 級創建同級頁碼 9。將記錄 (1010,10) 插入第 9 頁並將游標更改為此頁面。

    以此類推。在上面的示例中,資料庫在 0 級別提交到第 9 頁,在 1 級別提交到第 7 頁。

  • 我們現在有了一個完整的 B+-tree 索引,它是自下至上構建的!

  • 索引填充因子

    全局變數 innodb_fill_factor 用於設置插入 B-tree 頁中的空間量。默認值為 100,表示使用整個業面(不包括頁眉)。聚簇索引具有 innodb_fill_factor=100 的免除項。 在這種情況下,聚簇索引也空間的 1 /16 保持空閑。即 6.25% 的空間用於未來的 DML。

  • 值 80 意味著 MySQL 使用了 80% 的頁空間填充,預留 20% 於未來的更新。如果 innodb_fill_factor=100 則沒有剩餘空間供未來插入二級索引。如果在添加索引後,期望表上有更多的 DML,則可能導致業面拆分並再次合並。在這種情況下,建議使用 80-90 之間的值。此變數還會影響使用 OPTIMIZE TABLE 和 ALTER TABLE DROP COLUMN, ALGOITHM=INPLACE 重新創建的索引。也不應該設置太低的值,例如低於 50。因為索引會佔用浪費更多的磁碟空間,值較低時,索引中的頁數較多,索引統計信息的采樣可能不是最佳的。優化器可以選擇具有次優統計信息的錯誤查詢計劃。

  • 排序索引構建的優點

  • 沒有頁面拆分(不包括壓縮表)和合並

  • 沒有重復搜索插入位置

  • 插入不會被重做記錄(頁分配除外),因此重做日誌子系統的壓力較小

  • 缺點

  • ALTER 正在進行時,插入性能降低 Bug#82940,但在後續版本中計劃修復。

D. mysql innodb 索引到底是b+樹還是b樹

先從數據結構的角度來答。
題主應該知道B-樹和B+樹最重要的一個區別就是B+樹只有葉節點存放數據,其餘節點用來索引,而B-樹是每個索引節點都會有Data域。
這就決定了B+樹更適合用來存儲外部數據,也就是所謂的磁碟數據。
從Mysql(Inoodb)的角度來看,B+樹是用來充當索引的,一般來說索引非常大,尤其是關系性資料庫這種數據量大的索引能達到億級別,所以為了減少內存的佔用,索引也會被存儲在磁碟上。
那麼Mysql如何衡量查詢效率呢?磁碟IO次數,B-樹(B類樹)的特定就是每層節點數目非常多,層數很少,目的就是為了就少磁碟IO次數,當查詢數據的時候,最好的情況就是很快找到目標索引,然後讀取數據,使用B+樹就能很好的完成這個目的,但是B-樹的每個節點都有data域(指針),這無疑增大了節點大小,說白了增加了磁碟IO次數(磁碟IO一次讀出的數據量大小是固定的,單個數據變大,每次讀出的就少,IO次數增多,一次IO多耗時啊!),而B+樹除了葉子節點其它節點並不存儲數據,節點小,磁碟IO次數就少。這是優點之一。
另一個優點是什麼,B+樹所有的Data域在葉子節點,一般來說都會進行一個優化,就是將所有的葉子節點用指針串起來。這樣遍歷葉子節點就能獲得全部數據,這樣就能進行區間訪問啦。

至於MongoDB為什麼使用B-樹而不是B+樹,可以從它的設計角度來考慮,它並不是傳統的關系性資料庫,而是以Json格式作為存儲的nosql,目的就是高性能,高可用,易擴展。首先它擺脫了關系模型,上面所述的優點2需求就沒那麼強烈了,其次Mysql由於使用B+樹,數據都在葉節點上,每次查詢都需要訪問到葉節點,而MongoDB使用B-樹,所有節點都有Data域,只要找到指定索引就可以進行訪問,無疑單次查詢平均快於Mysql(但側面來看Mysql至少平均查詢耗時差不多)。

總體來說,Mysql選用B+樹和MongoDB選用B-樹還是以自己的需求來選擇的。

E. innodb 存儲引擎為什麼要用一個自增的主鍵

InnoDB 被稱為索引組織型的存儲引擎。主鍵使用的 B-Tree 來存儲數據,即錶行。這意味著 InnoDB 必須使用主鍵。如果表沒有主鍵,InnoDB 會向表中添加一個隱藏的自動遞增的 6 位元組計數器,並使用該隱藏計數器作為主鍵。InnoDB 的隱藏主鍵存在一些問題。您應該始終在表上定義顯式主鍵,並通過主鍵值訪問所有 InnoDB 行。InnoDB 的二級索引也是一個B-Tree。搜索關鍵字由索引列組成,存儲的值是匹配行的主鍵。通過二級索引進行搜索通常會導致主鍵的隱式搜索。

F. innodb存儲引擎支持全文索引嗎

innodb存儲引擎是不支持全文索引的,因為MySQL中的存儲引擎了解情況,InnoDB存儲引擎提供了具有提交、回滾和崩潰恢復能力的事務安全,但不支持全文索引。

G. Mysql資料庫3種存儲引擎有什麼區別

Mysql資料庫3種存儲(MyISAM、MEMORY、InnoDB)引擎區別:

1、Myisam是Mysql的默認存儲引擎,當create創建新表時,未指定新表的存儲引擎時,默認使用Myisam。MEMORY、InnoDB不是默認存儲引擎。

2、InnoDB存儲引擎提供了具有提交、回滾和崩潰恢復能力的事務安全。但是對比Myisam的存儲引擎,InnoDB寫的處理效率差一些並且會佔用更多的磁碟空間以保留數據和索引。

Mysql資料庫3種存儲(MyISAM、MEMORY、InnoDB)區別對比:

1、MyISAM
它不支持事務,也不支持外鍵,尤其是訪問速度快,對事務完整性沒有要求或者以SELECT、INSERT為主的應用基本都可以使用這個引擎來創建表。

數據文件和索引文件可以放置在不同的目錄,平均分配IO,獲取更快的速度。要指定數據文件和索引文件的路徑,需要在創建表的時候通過DATA DIRECTORY和INDEX DIRECTORY語句指定,文件路徑需要使用絕對路徑。

2、MEMORY

memory使用存在內存中的內容來創建表。每個MEMORY表實際對應一個磁碟文件,格式是.frm。MEMORY類型的表訪問非常快,因為它到數據是放在內存中的,並且默認使用HASH索引,但是一旦伺服器關閉,表中的數據就會丟失,但表還會繼續存在。

默認情況下,memory數據表使用散列索引,利用這種索引進行「相等比較」非常快,但是對「范圍比較」的速度就慢多了。因此,散列索引值適合使用在"="和"<=>"的操作符中,不適合使用在"<"或">"操作符中,也同樣不適合用在order by字句里。如果確實要使用"<"或">"或betwen操作符,可以使用btree索引來加快速度。

存儲在MEMORY數據表裡的數據行使用的是長度不變的格式,因此加快處理速度,這意味著不能使用BLOB和TEXT這樣的長度可變的數據類型。VARCHAR是一種長度可變的類型,但因為它在MySQL內部當作長度固定不變的CHAR類型,所以可以使用。

3、InnoDB
InnoDB存儲引擎提供了具有提交、回滾和崩潰恢復能力的事務安全。但是對比MyISAM的存儲引擎,InnoDB寫的處理效率差一些並且會佔用更多的磁碟空間以保留數據和索引。

(1)自動增長列:

InnoDB表的自動增長列可以手工插入,但是插入的如果是空或0,則實際插入到則是自動增長後到值。可以通過"ALTER TABLE...AUTO_INCREMENT=n;"語句強制設置自動增長值的起始值,默認為1,但是該強制到默認值是保存在內存中,資料庫重啟後該值將會丟失。

可以使用LAST_INSERT_ID()查詢當前線程最後插入記錄使用的值。如果一次插入多條記錄,那麼返回的是第一條記錄使用的自動增長值。對於InnoDB表,自動增長列必須是索引。如果是組合索引,也必須是組合索引的第一列,但是對於MyISAM表,自動增長列可以是組合索引的其他列,這樣插入記錄後,自動增長列是按照組合索引到前面幾列排序後遞增的。

(2)外鍵約束:
MySQL支持外鍵的存儲引擎只有InnoDB,在創建外鍵的時候,父表必須有對應的索引,子表在創建外鍵的時候也會自動創建對應的索引。

H. mysql的innodb引擎特點

1.插入緩沖(insert buffer)
插入緩沖(Insert Buffer/Change Buffer):提升插入性能,change buffering是insert buffer的加強,insert buffer只針對insert有效,change buffering對insert、delete、update(delete+insert)、purge都有效
只對於非聚集索引(非唯一)的插入和更新有效,對於每一次的插入不是寫到索引頁中,而是先判斷插入的非聚集索引頁是否在緩沖池中,如果在則直接插入;若不在,則先放到Insert Buffer 中,再按照一定的頻率進行合並操作,再寫回disk。這樣通常能將多個插入合並到一個操作中,目的還是為了減少隨機IO帶來性能損耗。
2.二次寫(double write)
Doublewrite緩存是位於系統表空間的存儲區域,用來緩存InnoDB的數據頁從innodb buffer pool中flush之後並寫入到數據文件之前,所以當操作系統或者資料庫進程在數據頁寫磁碟的過程中崩潰,Innodb可以在doublewrite緩存中找到數據頁的備份而用來執行crash恢復。數據頁寫入到doublewrite緩存的動作所需要的IO消耗要小於寫入到數據文件的消耗,因為此寫入操作會以一次大的連續塊的方式寫入
在應用(apply)重做日誌前,用戶需要一個頁的副本,當寫入失效發生時,先通過頁的副本來還原該頁,再進行重做,這就是double write
doublewrite組成:
內存中的doublewrite buffer,大小2M。
物理磁碟上共享表空間中連續的128個頁,即2個區(extend),大小同樣為2M。
對緩沖池的臟頁進行刷新時,不是直接寫磁碟,而是會通過memcpy()函數將臟頁先復制到內存中的doublewrite buffer,之後通過doublewrite 再分兩次,每次1M順序地寫入共享表空間的物理磁碟上,在這個過程中,因為doublewrite頁是連續的,因此這個過程是順序寫的,開銷並不是很大。在完成doublewrite頁的寫入後,再將doublewrite buffer 中的頁寫入各個 表空間文件中,此時的寫入則是離散的。如果操作系統在將頁寫入磁碟的過程中發生了崩潰,在恢復過程中,innodb可以從共享表空間中的doublewrite中找到該頁的一個副本,將其復制到表空間文件,再應用重做日誌。
3.自適應哈希索引(ahi)
Adaptive Hash index屬性使得InnoDB更像是內存資料庫。該屬性通過innodb_adapitve_hash_index開啟,也可以通過—skip-innodb_adaptive_hash_index參數
關閉
Innodb存儲引擎會監控對表上二級索引的查找,如果發現某二級索引被頻繁訪問,二級索引成為熱數據,建立哈希索引可以帶來速度的提升
經常訪問的二級索引數據會自動被生成到hash索引裡面去(最近連續被訪問三次的數據),自適應哈希索引通過緩沖池的B+樹構造而來,因此建立的速度很快。
哈希(hash)是一種非常快的等值查找方法,在一般情況下這種查找的時間復雜度為O(1),即一般僅需要一次查找就能定位數據。而B+樹的查找次數,取決於B+樹的高度,在生產環境中,B+樹的高度一般3-4層,故需要3-4次的查詢
4.預讀(read ahead)
InnoDB使用兩種預讀演算法來提高I/O性能:線性預讀(linear read-ahead)和隨機預讀(randomread-ahead)
為了區分這兩種預讀的方式,我們可以把線性預讀放到以extent為單位,而隨機預讀放到以extent中的page為單位。線性預讀著眼於將下一個extent提前讀取到buffer pool中,而隨機預讀著眼於將當前extent中的剩餘的page提前讀取到buffer pool中