日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

数据库索引是什么?为什么要使用索引?

發(fā)布時(shí)間:2024/8/1 数据库 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据库索引是什么?为什么要使用索引? 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

數(shù)據(jù)庫(kù)索引:

索引(index)是幫助MySQL高效獲取數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)(有效),在數(shù)據(jù)之外,數(shù)據(jù)庫(kù)系統(tǒng)還維護(hù)著滿足特定查找算法的數(shù)據(jù)結(jié)構(gòu),這些數(shù)據(jù)結(jié)構(gòu)以某種方式引用(指向)數(shù)據(jù), 這樣就可以在這些數(shù)據(jù)結(jié)構(gòu)上實(shí)現(xiàn)高級(jí)查找算法,這種數(shù)據(jù)結(jié)構(gòu)就是索引。簡(jiǎn)而言之:幫助MySQL高效的查詢出數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)叫做索引。

索引的優(yōu)勢(shì):

  • 索引類似于書籍的目錄,提高數(shù)據(jù)檢索的效率,減少數(shù)據(jù)庫(kù)IO的成本

  • 通過(guò)索引列對(duì)數(shù)據(jù)進(jìn)行排序,降低數(shù)據(jù)排序的成本,降低CPU的消耗

  • 索引的劣勢(shì):

  • 實(shí)際上索引也是一張表,存儲(chǔ)在磁盤上,該表保存了主鍵與索引字段,并指向?qū)嶓w類的記錄

  • 雖然索引大大提高了查詢的速度,但是降低了增刪改的速度,對(duì)表進(jìn)行update、insert、delete時(shí),需要對(duì)索引文件進(jìn)行更新

  • 從四點(diǎn)講述索引功能:

  • 為什么要給表加上主鍵?

  • 為什么加索引后會(huì)使查詢變快?

  • 為什么加索引后會(huì)使寫入、修改、刪除變慢?

  • 什么情況下要同時(shí)在兩個(gè)字段上建索引?

  • 首先我們想要了解索引的原理我們需要清楚一種數(shù)據(jù)結(jié)構(gòu)(平衡樹(shù))也就是b tree或者 b+ tree ,當(dāng)然,
    有的數(shù)據(jù)庫(kù)也使用哈希桶作用索引的數(shù)據(jù)結(jié)構(gòu), 然而,主流的RDBMS(關(guān)系型數(shù)據(jù)庫(kù))都是把平衡樹(shù)當(dāng)做數(shù)據(jù)表默認(rèn)的索引數(shù)據(jù)結(jié)構(gòu)的

    聚集索引與非聚集索引

    我們平時(shí)建表的時(shí)候都會(huì)為表加上主鍵, 在某些關(guān)系數(shù)據(jù)庫(kù)中, 如果建表時(shí)不指定主鍵,數(shù)據(jù)庫(kù)會(huì)拒絕建表的語(yǔ)句執(zhí)行。
    如果定義了主鍵,InnoDB會(huì)自動(dòng)使用主鍵來(lái)創(chuàng)建聚集索引。如果沒(méi)有定義主鍵,InnoDB會(huì)選擇一個(gè)唯一的非空索引代替主鍵。如果沒(méi)有唯一的非空索引,InnoDB會(huì)隱式定義一個(gè)主鍵來(lái)作為聚集索引。)

    MyISAM:

    B+Tree葉節(jié)點(diǎn)存放的是數(shù)據(jù)記錄的地址,在檢索的時(shí)候,先找到索引對(duì)應(yīng)的數(shù)據(jù)記錄的地址,再根據(jù)地址讀取相應(yīng)的數(shù)據(jù)記錄,這種查找方式被稱為“非聚集索引”。

    InnoDB:

    它的主鍵索引是聚集索引,即主鍵和行記錄放在同一個(gè)葉節(jié)點(diǎn),找到了主鍵也就找到了行記錄;而它的非主鍵索引,或者說(shuō)是輔助索引,是非聚集索引,跟MyISAM引擎的非聚集索引不同的是,MyISAM葉節(jié)點(diǎn)保存的是地址,而InnoDB是主鍵,InnoDB非聚集索引的索引文件和數(shù)據(jù)文件分開(kāi)存儲(chǔ),索引文件的葉節(jié)點(diǎn)只保存主鍵,在查找時(shí),要先找到葉節(jié)點(diǎn)中的主鍵,再根據(jù)主鍵去主索引文件查找詳細(xì)行記錄;因此,在設(shè)計(jì)表的時(shí)候,主鍵字段不宜過(guò)長(zhǎng)。

    為什么要給表加上主鍵?

    事實(shí)上, 一個(gè)加了主鍵的表,并不能被稱之為「表」。
    一個(gè)沒(méi)加主鍵的表,它的數(shù)據(jù)無(wú)序的放置在磁盤存儲(chǔ)器上,一行一行的排列的很整齊
    如果給表上了主鍵,那么表在磁盤上的存儲(chǔ)結(jié)構(gòu)就由整齊排列的結(jié)構(gòu)轉(zhuǎn)變成了樹(shù)狀結(jié)構(gòu), 也就是上面說(shuō)的「平衡樹(shù)」結(jié)構(gòu)
    換句話說(shuō),就是整個(gè)表就變成了一個(gè)索引,是所謂的「聚集索引」。
    這就是為什么一個(gè)表只能有一個(gè)主鍵,一個(gè)表只能有一個(gè)「聚集索引」,因?yàn)橹麈I的作用就是把「表」的數(shù)據(jù)格式轉(zhuǎn)換成「索引(平衡樹(shù))」的格式放置。

    為什么加索引后會(huì)使查詢變快?

    其中樹(shù)的所有結(jié)點(diǎn)(底部除外)的數(shù)據(jù)都是由主鍵字段中的數(shù)據(jù)構(gòu)成,也就是通常我們指定主鍵的id字段。最下面部分是真正表中的數(shù)據(jù)。

    假如我們執(zhí)行一個(gè)SQL語(yǔ)句: select * from table where id = 1256;
    首先根據(jù)索引定位到1256這個(gè)值所在的葉結(jié)點(diǎn),然后再通過(guò)葉結(jié)點(diǎn)取到id等于1256的數(shù)據(jù)行。
    這里不講解平衡樹(shù)的運(yùn)行細(xì)節(jié), 但是從上圖能看出,樹(shù)一共有三層, 從根節(jié)點(diǎn)至葉節(jié)點(diǎn)只需要經(jīng)過(guò)三次查找就能得到結(jié)果。如下圖

    假如一張表有一億條數(shù)據(jù) ,需要查找其中某一條數(shù)據(jù),按照常規(guī)邏輯, 一條一條的去匹配的話,
    最壞的情況下需要匹配一億次才能得到結(jié)果,用大O標(biāo)記法就是O(n)最壞時(shí)間復(fù)雜度,這是無(wú)法接受的,而且這一億條數(shù)據(jù)顯然不能一次性讀入內(nèi)存供程序使用。
    因此, 這一億次匹配在不經(jīng)緩存優(yōu)化的情況下就是一億次IO開(kāi)銷,以現(xiàn)在磁盤的IO能力和CPU的運(yùn)算能力, 有可能需要幾個(gè)月才能得出結(jié)果。
    如果把這張表轉(zhuǎn)換成平衡樹(shù)結(jié)構(gòu)(一棵非常茂盛和節(jié)點(diǎn)非常多的樹(shù)),假設(shè)這棵樹(shù)有10層,那么只需要10次IO開(kāi)銷就能查找到所需要的數(shù)據(jù), 速度以指數(shù)級(jí)別提升。
    n是記錄總樹(shù),底數(shù)是樹(shù)的分叉數(shù),結(jié)果就是樹(shù)的層次數(shù)。換言之,查找次數(shù)是以樹(shù)的分叉數(shù)為底,記錄總數(shù)的對(duì)數(shù),用公式來(lái)表示就是

    用程序來(lái)表示就是Math.Log(100000000,10),100000000是記錄數(shù),10是樹(shù)的分叉數(shù)(真實(shí)環(huán)境下分叉數(shù)遠(yuǎn)不止10),
    結(jié)果就是查找次數(shù),這里的結(jié)果從億降到了個(gè)位數(shù)。因此,利用索引會(huì)使數(shù)據(jù)庫(kù)查詢有驚人的性能提升。

    為什么加索引后會(huì)使寫入、修改、刪除變慢?

    然而, 事物都是有兩面的, 索引能讓數(shù)據(jù)庫(kù)查詢數(shù)據(jù)的速度上升, 而使寫入數(shù)據(jù)的速度下降,原因很簡(jiǎn)單的,
    因?yàn)槠胶鈽?shù)這個(gè)結(jié)構(gòu)必須一直維持在一個(gè)正確的狀態(tài), 增刪改數(shù)據(jù)都會(huì)改變平衡樹(shù)各節(jié)點(diǎn)中的索引數(shù)據(jù)內(nèi)容,破壞樹(shù)結(jié)構(gòu), 因此,在每次數(shù)據(jù)改變時(shí),
    DBMS必須去重新梳理樹(shù)(索引)的結(jié)構(gòu)以確保它的正確,這會(huì)帶來(lái)不小的性能開(kāi)銷,也就是為什么索引會(huì)給查詢以外的操作帶來(lái)副作用的原因。

    講完聚集索引 , 接下來(lái)聊一下非聚集索引, 也就是我們平時(shí)經(jīng)常提起和使用的常規(guī)索引。

    非聚集索引和聚集索引一樣, 同樣是采用平衡樹(shù)作為索引的數(shù)據(jù)結(jié)構(gòu)。索引樹(shù)結(jié)構(gòu)中各節(jié)點(diǎn)的值來(lái)自于表中的索引字段。
    假如給user表的name字段加上索引 , 那么索引就是由name字段中的值構(gòu)成,在數(shù)據(jù)改變時(shí), DBMS需要一直維護(hù)索引結(jié)構(gòu)的正確性。如果給表中多個(gè)字段加上索引 , 那么就會(huì)出現(xiàn)多個(gè)獨(dú)立的索引結(jié)構(gòu),每個(gè)索引(非聚集索引)互相之間不存在關(guān)聯(lián)。
    如下圖

    每次給字段建一個(gè)新索引, 字段中的數(shù)據(jù)就會(huì)被復(fù)制一份出來(lái), 用于生成索引。 因此, 給表添加索引,會(huì)增加表的體積, 占用磁盤存儲(chǔ)空間。

    非聚集索引和聚集索引的區(qū)別在于, 通過(guò)聚集索引可以查到需要查找的數(shù)據(jù), 而通過(guò)非聚集索引可以查到記錄對(duì)應(yīng)的主鍵值 ,
    再使用主鍵的值通過(guò)聚集索引查找到需要的數(shù)據(jù),如下圖

    不管以任何方式查詢表, 最終都會(huì)利用主鍵通過(guò)聚集索引來(lái)定位到數(shù)據(jù), 聚集索引(主鍵)是通往真實(shí)數(shù)據(jù)所在的唯一路徑。

    然而, 有一種例外可以不使用聚集索引就能查詢出所需要的數(shù)據(jù), 這種非主流的方法 稱之為「覆蓋索引」查詢。
    也就是平時(shí)所說(shuō)的復(fù)合索引或者多字段索引查詢。 文章上面的內(nèi)容已經(jīng)指出, 當(dāng)為字段建立索引以后, 字段中的內(nèi)容會(huì)被同步到索引之中。
    如果為一個(gè)索引指定兩個(gè)字段, 那么這個(gè)兩個(gè)字段的內(nèi)容都會(huì)被同步至索引之中。

    先看下面這個(gè)SQL語(yǔ)句

    //建立索引

    create index index_birthday on user_info(birthday);

    //查詢生日在1991年11月1日出生用戶的用戶名

    select user_name from user_info where birthday = ‘1991-11-1’

    這句SQL語(yǔ)句的執(zhí)行過(guò)程如下

    首先,通過(guò)非聚集索引index_birthday查找birthday等于1991-11-1的所有記錄的主鍵ID值

    然后,通過(guò)得到的主鍵ID值執(zhí)行聚集索引查找,找到主鍵ID值對(duì)就的真實(shí)數(shù)據(jù)(數(shù)據(jù)行)存儲(chǔ)的位置

    最后, 從得到的真實(shí)數(shù)據(jù)中取得user_name字段的值返回, 也就是取得最終的結(jié)果

    什么情況下要同時(shí)在兩個(gè)字段上建索引?

    我們把birthday字段上的索引改成雙字段的覆蓋索引

    create index index_birthday_and_user_name on user_info(birthday,
    user_name);

    這句SQL語(yǔ)句的執(zhí)行過(guò)程就會(huì)變?yōu)?/p>

    通過(guò)非聚集索引index_birthday_and_user_name查找birthday等于1991-11-1的葉節(jié)點(diǎn)的內(nèi)容,然而,
    葉節(jié)點(diǎn)中除了有user_name表主鍵ID的值以外, user_name字段的值也在里面, 因此不需要通過(guò)主鍵ID值的查找數(shù)據(jù)行的真實(shí)所在,
    直接取得葉節(jié)點(diǎn)中user_name的值返回即可。 通過(guò)這種覆蓋索引直接查找的方式, 可以省略不使用覆蓋索引查找的后面兩個(gè)步驟,
    大大的提高了查詢性能,如下圖

    總結(jié)

    以上是生活随笔為你收集整理的数据库索引是什么?为什么要使用索引?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。