深入淺出資料庫索引

2020-12-17 成長之路

金三銀四,每年的這個時候都是求職招聘的黃金期,很不幸,我也加入了這個浩浩蕩蕩的求職大軍中。每每面試,都會問到:你是如何使用索引的?聚集索引和非聚集索引的區別是什麼?為什麼使用索引會查詢快?等等等等一系列的索引問題,恰巧平時使用索引都是哪個欄位常用做查詢就加上索引,不知其所以然。回來深入研究,把學習筆記和大家分享,希望給你帶來幫助。

在學習索引之前,我們拋出以下六個問題,如果你都能解答出來,那這篇文章就不用看了,你的索引已經學成了

為什麼要給表加上主鍵?為什麼加索引後會使查詢變快?為什麼加索引後會使寫入、修改、刪除變慢?什麼情況下要同時在兩個欄位上建索引? 聚合索引為什麼比非聚合索引查詢快?索引越多越好嗎?

索引的原理

一個表中沒有主鍵,數據是無序的放置在磁碟存儲器上,一行一行的排列的很整齊,加上了主鍵,表在磁碟上的存儲結構就由整齊排列的結構轉變成了 樹狀結構(B+ Tree),換句話說整個表就變成了了一個索引,也就是聚集索引,這就是為什麼一個表只能有一個主鍵,一個表只能有一個聚集索引,因為主鍵的作用就是把表的數據格式轉換成索引的格式放置。

圖來源於網絡

根據索引定位到值所在的葉結點,然後再通過葉結點取到數據行。所以為什麼加索引查詢效率會高,就是這個原因。

圖來源於網絡

然而, 事物都是有兩面的, 索引能讓資料庫查詢數據的速度上升, 而使寫入數據的速度下降,原因很簡單的, 因為平衡樹這個結構必須一直維持在一個正確的狀態, 增刪改數據都會改變平衡樹各節點中的索引數據內容,破壞樹結構, 因此,在每次數據改變時, DBMS必須去重新梳理樹(索引)的結構以確保它的正確,這會帶來不小的性能開銷,也就是為什麼索引會給查詢以外的操作帶來副作用的原因(索引不是越多越好的第一個原因)。

非聚集索引和聚集索引一樣, 同樣是採用平衡樹作為索引的數據結構。索引樹結構中各節點的值來自於表中的索引欄位, 假如給user表的name欄位加上索引 , 那麼索引就是由name欄位中的值構成,在數據改變時, DBMS需要一直維護索引結構的正確性。如果給表中多個欄位加上索引 , 那麼就會出現多個獨立的索引結構,每個索引(非聚集索引)互相之間不存在關聯。 如下圖

圖來源於網絡

每次給欄位建一個新索引, 欄位中的數據就會被複製一份出來, 用於生成索引。 因此, 給表添加索引,會增加表的體積, 佔用磁碟存儲空間,這也就是索引不是越多越好的第二個原因

非聚集索引和聚集索引的區別在於, 通過聚集索引可以查到需要查找的數據, 而通過非聚集索引可以查到記錄對應的主鍵值 , 再使用主鍵的值通過聚集索引查找到需要的數據,如下圖

圖來源於網絡

不管以任何方式查詢表, 最終都會利用主鍵通過聚集索引來定位到數據, 聚集索引(主鍵)是通往真實數據所在的唯一路徑。這就是聚合索引比非聚合索引效率高的原因。

是否不使用聚集索引就能查詢出所需要的數據呢?答案是肯定的, 這種非主流的方法 稱之為「覆蓋索引」查詢, 也就是平時所說的複合索引或者多欄位索引查詢。 當為欄位建立索引以後, 欄位中的內容會被同步到索引之中, 如果為一個索引指定兩個欄位, 那麼這個兩個欄位的內容都會被同步至索引之中

舉例:一個表,有id,姓名,生日,年齡等欄位,姓名和生日組成複合索引index_birthday_and_user_name,通過非聚集索引index_birthday_and_user_name查找birthday等於1991-11-1的葉節點的內容,然而, 葉節點中除了有user_name表主鍵ID的值以外, user_name欄位的值也在裡面, 因此不需要通過主鍵ID值的查找數據行的真實所在, 直接取得葉節點中user_name的值返回即可。 通過這種覆蓋索引直接查找的方式, 可以省略不使用覆蓋索引查找的後面兩個步驟, 大大的提高了查詢性能,如下圖

圖來源於網絡

使用索引的技巧

1.索引不會包含有NULL的列

只要列中包含有NULL值,都將不會被包含在索引中,複合索引中只要有一列含有NULL值,那麼這一列對於此符合索引就是無效的。

2.使用短索引

對串列進行索引,如果可以就應該指定一個前綴長度。例如,如果有一個char(255)的列,如果在前10個或20個字符內,多數值是唯一的,那麼就不要對整個列進行索引。短索引不僅可以提高查詢速度而且可以節省磁碟空間和I/O操作。

3.索引列排序

mysql查詢只使用一個索引,因此如果where子句中已經使用了索引的話,那麼order by中的列是不會使用索引的。因此資料庫默認排序可以符合要求的情況下不要使用排序操作,儘量不要包含多個列的排序,如果需要最好給這些列建複合索引。

4.like語句操作

一般情況下不鼓勵使用like操作,如果非使用不可,注意正確的使用方式。like 『%aaa%』不會使用索引,而like 『aaa%』可以使用索引。

5.不要在列上進行運算

6.不使用NOT IN 、<>、!=操作,但<,<=,=,>,>=,BETWEEN,IN是可以用到索引的

7.索引要建立在經常進行select操作的欄位上。

這是因為,如果這些列很少用到,那麼有無索引並不能明顯改變查詢速度。相反,由於增加了索引,反而降低了系統的維護速度和增大了空間需求。

8.索引要建立在值比較唯一的欄位上。

9.對於那些定義為text、image和bit數據類型的列不應該增加索引。因為這些列的數據量要麼相當大,要麼取值很少。

10.在where和join中出現的列需要建立索引。

11.where的查詢條件裡有不等號(where column != …),mysql將無法使用索引。

12.如果where字句的查詢條件裡使用了函數(如:where DAY(column)=…),mysql將無法使用索引。

13.在join操作中(需要從多個數據表提取數據時),mysql只有在主鍵和外鍵的數據類型相同時才能使用索引,否則及時建立了索引也不會使用

全文索引

舊版的MySQL的全文索引只能用在MyISAM, 不過新版的MySQL5.6.24上InnoDB引擎也加入了全文索引

欄位類型:char、varchar和text

創建全文索引(1)創建表的同時創建全文索引 CREATE TABLE article ( id INT AUTO_INCREMENT NOT NULL PRIMARY KEY, title VARCHAR(200), body TEXT, FULLTEXT(title, body) ) 建立的索引名 是「title」(2)通過 alter table 的方式來添加 ALTER TABLE `student` ADD FULLTEXT INDEX ft_stu_name (`name`) #ft_stu_name是索引名,可以隨便起 或者:ALTER TABLE `student` ADD FULLTEXT ft_stu_name (`name`)(3)直接通過create index的方式 CREATE FULLTEXT INDEX ft_email_name ON `student` (`name`) 也可以在創建索引的時候指定索引的長度: CREATE FULLTEXT INDEX ft_email_name ON `student` (`name`(20)刪除全文索引(1)直接使用 drop index DROP INDEX 索引名稱 ON 表名;(2)使用 alter table的方式 ALTER TABLE 表名 DROP INDEX 索引名稱;使用全文索引跟普通索引稍有不同,使用全文索引的格式: MATCH (columnName) AGAINST ('string')SELECT * FROM `student` WHERE MATCH(`name`) AGAINST('聰')當查詢多列數據時: 建議在此多列數據上創建一個聯合的全文索引,否則使用不了索引的。 SELECT * FROM `student` WHERE MATCH(`name`,`address`) AGAINST('聰 廣東')使用全文索引需要注意的是:(基本單位是詞)分詞,全文索引以詞為基礎的,MySQL默認的分詞是所有非字母和數字的特殊符號都是分詞符(外國人嘛)MySQL中與全文索引相關的幾個變量使用命令:mysql> SHOW VARIABLES LIKE 'ft%'; #ft就是FullText的簡寫

ft_boolean_syntax + -><()~*:""&| #改變IN BOOLEAN MODE的查詢字符,不用重新啟動MySQL也不用重建索引 ft_min_word_len 4 #最短的索引字符串,默認值為4,(通常改為1)修改後必須重建索引文件,重新建立索引命令:repair table tablename quick

ft_max_word_len 84 #最長的索引字符串,默認值為84,修改後必須重建索引文件

ft_query_expansion_limit 20 #查詢括展時取最相關的幾個值用作二次查詢

ft_stopword_file (built-in)#全文索引的過濾詞文件,共545個默認詞

(1)ft_boolean_syntax (+ -><()~*:""&|)使用的詳解

IN BOOLEAN MODE自己百度查

SELECT * FROM `student` WHERE MATCH(`name`) AGAINST('' IN BOOLEAN MODE)

(2)+ : 用在詞的前面,表示一定要包含該詞,並且必須在開始位置。

eg: +Apple 匹配:Apple123, "tommy, Apple"

(3)- : 不包含該詞,所以不能單獨用,這樣是查不到任何row的,必須搭配其他語法使用

eg: MATCH (girl_name) AGAINST ('-林志玲 +張筱雨') 匹配到: 所有不包含林志玲,但包含張筱雨的記錄

(4)空(也就是默認情況),表示可選的,包含該詞的順序較高。

apple banana找至少包含上面詞中的一個的記錄行

+apple +juice兩個詞均在被包含

+apple mac包含詞 「apple」,但是如果同時包含 「mac」,它的排列將更高一些

+apple -macintosh 包含 「apple」 但不包含 「macintosh」

(5)> :提高該字的相關性,查詢的結果會排在比較靠前的位置。

(6)< :降低相關性,查詢的結果會排在比較靠後的位置。

(7):可以通過括號來使用字條件。

eg: +aaa +(>bbb <ccc) // 找到有aaa和bbb和ccc,aaa和bbb,或者aaa和ccc(因為bbb,ccc前面沒有+,所以表示可有可無),然後 aaa&bbb > aaa&bbb&ccc > aaa&ccc

(8)~ :將其相關性由正轉負,表示擁有該字會降低相關性,但不像「-」將之排除,只是排在較後面。

eg: +apple ~macintosh 先匹配apple,但如果同時包含macintosh,就排名會靠後。

(9)* :通配符,這個只能接在字符串後面。

MATCH (girl_name) AGAINST ('+*ABC*') #錯誤,不能放前面MATCH (girl_name) AGAINST ('+張筱雨*') #正確

(10)" " :整體匹配,用雙引號將一段句子包起來表示要完全相符,不可拆字。

eg: "tommy huang" 可以匹配 tommy huangxxxxx 但是不能匹配 tommy is huang

B+樹索引和哈希索引的區別

B+樹是一個平衡的多叉樹,從根節點到每個葉子節點的高度差值不超過1,而且同層級的節點間有指針相互連結

哈希索引就是採用一定的哈希算法,把鍵值換算成新的哈希值,檢索時不需要類似B+樹那樣從根節點到葉子節點逐級查找,只需一次哈希算法即可立刻定位到相應的位置,速度非常快。

B+樹索引和哈希索引的明顯區別是:

· 如果是等值查詢,那麼哈希索引明顯有絕對優勢,因為只需要經過一次算法即可找到相應的鍵值;當然了,這個前提是,鍵值都是唯一的。如果鍵值不是唯一的,就需要先找到該鍵所在位置,然後再根據鍊表往後掃描,直到找到相應的數據;

· 從示意圖中也能看到,如果是範圍查詢檢索,這時候哈希索引就毫無用武之地了,因為原先是有序的鍵值,經過哈希算法後,有可能變成不連續的了,就沒辦法再利用索引完成範圍查詢檢索;

· 同理,哈希索引也沒辦法利用索引完成排序,以及like 『xxx%』 這樣的部分模糊查詢(這種部分模糊查詢,其實本質上也是範圍查詢);

· 哈希索引也不支持多列聯合索引的最左匹配規則

· B+樹索引的關鍵字檢索效率比較平均,不像B樹那樣波動幅度大,在有大量重複鍵值情況下,哈希索引的效率也是極低的,因為存在所謂的哈希碰撞問題

索引為什麼使用B+Tree ,而不使用二叉樹來實現

其實從算法邏輯上講,二叉查找樹的查找速度和比較次數都是最小的,但是從Mysql的角度講,我們不得不考慮一個現實問題:磁碟IO。

查找都是索引操作,一般來說索引非常大,尤其是關係型資料庫這種,當數據量比較大的時候,索引的大小有可能幾個G甚至更多,數據量大的索引能達到億級別,所以為了減少內存的佔用,資料庫索引是存儲在外部磁碟上的。

當我們利用索引查詢的時候,不可能把整個索引全部加載到內存,只能逐一加載每個磁碟頁,磁碟頁對應索引樹的節點,為了減少磁碟IO的次數,就需要儘量降低樹的高度

相關焦點

  • 從原理到優化,深入淺出資料庫索引 - 計算機java編程
    MySQL官方對索引的定義為:索引(Index)是幫助MySQL高效獲取數據的數據結構。資料庫查詢是資料庫的最主要功能之一,我們都希望查詢數據的速度能儘可能的快,因此資料庫系統的設計者會從查詢算法的角度進行優化,這篇文章對索引做一個系統的梳理,希望對大家有幫助。
  • 一文讀懂資料庫索引
    一、啥是索引資料庫索引是建立在表的一列或多個列上的輔助對象,用於加快數據的檢索,類似於書籍的索引。當資料庫表中的數據越來越多的時候,查詢效率變慢,這時候我們就需要資料庫索引了。3、主鍵索引(PRIMAY KEY)主鍵索引是一種特殊的唯一索引,將索引建在主鍵上,不允許NULL值。4、組合索引組合索引是多列值組成一個索引,專門用於組合搜索,效率大於索引合併。
  • 「中文學術集刊索引資料庫」正式上線
    【來源:光明網】4月9日,由南京大學中國社會科學研究評價中心打造的「中文學術集刊索引資料庫」正式上線。該資料庫的推出是在CSSCI期刊索引和圖書索引建成之後的又一重要成果,標誌著我國人文社會科學科研評價體系和方法的改革又向前邁出了重要一步。
  • MySQL資料庫SQL優化技巧四之索引
    #MYSQL#和表一樣,索引和視圖也是資料庫中的重要對象本篇將介紹索引的概念。剛開始都是一些概念性的東西,需要去了解,可能是比較枯燥乏味的,但是這些概念的東西還是需要知道的,了解來龍去脈才能知其所以然。大概還有兩篇就能到真正的乾貨環節。1索引的基礎知識用戶對數署庫最頻繁的操作是數據查詢。-般情況下,資料庫在進行查詢操作時,霜嬰對整個表進行搜索。
  • 千萬級MySQL資料庫這樣建索引可以讓你的資料庫飛起來
    另外,過多的複合索引,在有單欄位索引的情況下,一般都是沒有存在價值的;相反,還會降低數據增加刪除時的性能,特別是對頻繁更新的表來說,負面影響更大。總的來說,小型表肯定不建索引,或者資料庫記錄在億條數據級以上,還是建議使用非關係型資料庫。
  • 超全的資料庫建表、SQL、索引規範
    因為工作崗位的原因,負責制定了關於後端組資料庫的規約規範,作為所有產品線的規範,歷經幾版的修改,最終形成下邊的文本,規範在整個後端執行也有大半年的時間,對於整個團隊在開發階段就減少不恰當的建表語句、錯誤SQL、錯誤的索引有積極的意義,故分享出來給大家參考。
  • 索引,一文搞定 | 資料庫系列
    前段時間寫資料庫內核比較多,最近又有朋友問索引的應用了,其實相關索引應用之前或多或少寫過
  • 資料庫面試題:唯一索引和普通索引選哪個?MySQL的優化 -開課吧
    資料庫面試題唯索引和普通索引選擇哪個?唯索引和普通索引在讀取的時候效率基本差不多,普通索引差了點點。主要是判斷和特殊情況下的次IO。寫的時候,普通索引可以利change buffffer適合寫多讀少,唯索引要快。以業務為前提,如果要求唯,就要選擇唯索引。如果已經保證列的唯,我們儘量選擇普通索引,然後把 change buffffer 調。
  • 為什麼資料庫使用有序索引,而程式設計師卻在使用哈希表?
    為什麼程序和資料庫之間的「默認」選擇會產生不同呢?然而,資料庫默認總是會使用有序索引,通常是B樹。為什麼程序和資料庫之間的「默認」選擇會產生不同呢?說到底兩者都是為了同一個目標:訪問數據。一年前,我曾就這個問題在Twitter上發表了推文,並得到了許多有趣的答案。下面就來總結一下我得到的答案。常見的答案是,當在內存中存儲數據時,哈希表的效率很高,而B樹的設計旨在以塊的形式訪問較慢的存儲。然而,這不是決定性的屬性。
  • MySQL資料庫SQL優化技巧五之非聚集索引
    和最基本的索引的創建語法。索弓|的創建與銷毀在SQL中,創建索引是由CREATE INDEX關鍵字實現的。但在不同的資料庫管理系統中,CREATE INDEX語句有不同形式的擴展。索引的銷毀則是由DROP INDEX關鍵字實現的。
  • SQL-資料庫索引選擇B+樹的原因
    在進一步分析為什麼MySQL資料庫索引選擇使用B+樹之前,我相信很多小夥伴對數據結構中的樹還是有些許模糊的,因此我們由淺入深一步步探討樹的演進過程,在一步步引出B樹以及為什麼MySQL資料庫索引選擇使用B+樹!學過數據結構的一般對最基礎的樹都有所認識,因此我們就從與我們主題更為相近的二叉查找樹開始。
  • 資料庫支招:Oracle創建/重建和刪除索引
    為了方便廣大考生更好的複習,幫考網綜合整理提供了Oracle認證:Oracle創建/重建和刪除索引,以供各位考生考試複習參考,希望對考生複習有所幫助。Oracle創建、重建和刪除索引創建索引:SQL》 create index mcconf_index on mc$ma_warn_config (NAME);Index created.
  • 資料庫索引的知識點,你所需要了解的都在這兒了
    資料庫索引,相信大家都不陌生吧。索引是對資料庫表中一列或多列的值進行排序的一種結構,使用索引可快速訪問資料庫表中的特定信息。首先聲明一下,本文索引的知識點全部是基於MySQL資料庫索引的優缺點優點:1.大大加快數據的查詢速度2.唯一索引可以保證資料庫表每一行的唯一性
  • 《天然氣地球科學》被美國《工程索引》(EI)資料庫收錄
    Elsevier二次文獻數據部(EI中國辦事處)通知,美國《工程索引》(Engineering Index,EI)資料庫自2013年起將《天然氣地球科學》(雙月刊)雜誌作為收錄源期刊。Elsevier二次文獻數據部主要工作是為Elsevier二次文獻資料庫(包括Scopus、Ei Compendex、Geobase、Embase 等)處理中國期刊的二次文獻數據(文章的題目,作者信息,摘要和參考文獻)。《工程索引》資料庫,創建於1884年,是目前全球最著名的三大文摘類檢索資料庫(SCI、EI、INSPPC)之一。
  • 超全的資料庫建表/SQL/索引規範,建議貼在工位上!
    「背景」因為工作崗位的原因,負責制定了關於後端組資料庫的規約規範,作為所有產品線的規範,歷經幾版的修改,最終形成下邊的文本。「【強制】(4) 資料庫表、表欄位必須加入中文注釋」解讀:大家都別懶。,增加資料庫處理記錄的複雜性;同等條件下,表中有較多空欄位的時候,資料庫的處理性能會降低很多;NULL值需要更多的存儲空,無論是表還是索引中每行中的NULL的列都需要額外的空間來標識。
  • 單個ibdata1文件包含MySQL資料庫中的所有表和索引
    在本教程中,我們將說明如何重建整個MySQL資料庫,以及如何將較大的MySQL系統表空間文件分解為較小的單個MySQL表文件。在MySQL中,當您使用InnoDB時,所有表和索引都存儲在MySQL系統表空間下。MySQL系統表空間是ibdata1,位於/ var / lib / mysql下
  • mysql資料庫的索引類型
    MySQL索引類型:1、普通索引最基本的索引,它沒有任何限制,用於加速查詢。創建方法:a. >索引列的值必須唯一,但允許有空值。指多個欄位上創建的索引,只有在查詢條件中使用了創建索引時的第一個欄位,索引才會被使用。
  • 深入淺出 spring-data-elasticsearch 之 ElasticSearch 架構初探(一)
    索引(Index)索引,用於區分文檔成組,即分到一組的文檔集合。索引,用於存儲文檔和使文檔可被搜索。比如項目存索引 project 裡面,交易存索引 sales 等。類型(Type)類型,用於區分索引中的文檔,即在索引中對數據邏輯分區。比如索引 project 的項目數據,根據項目類型 ui 項目、插畫項目等進行區分。
  • MySQL索引與索引優化
    索引是對資料庫表中一個或多個列的值進行排序的結構,建立索引有助於快速獲取信息。你也可以這樣理解:索引就是加快檢索表中數據的方法。資料庫的索引類似於書籍的索引。在書籍中,索引允許用戶不必翻閱完整個書就能迅速地找到所需要的信息。在資料庫中,索引也允許資料庫程序迅速地找到表中的數據,而不必掃描整個資料庫。
  • 一文看懂聚集索引和非聚集索引的區別
    及時獲取有趣有料的技術文章原文地址:https://blog.csdn.net/riemann_/article/details/90324846一、深入淺出理解索引結構實際上,可以把索引理解為一種特殊的目錄。