簡單談談資料庫索引

来源:http://www.cnblogs.com/xiaoming0601/archive/2016/10/13/5956077.html
-Advertisement-
Play Games

最近筆試面試特別多的都問到了資料庫索引,由於之前並沒有單獨做系統的複習,導致許多關於索引的知識點記憶的很模糊,今天整理下相關筆記(並沒有深挖,對於初學者還是可以看看的),僅供參考。 什麼是索引 資料庫索引好比是一本書前面的目錄,能加快資料庫的查詢速度。 例如這樣一個查詢:select * from ...


  最近筆試面試特別多的都問到了資料庫索引,由於之前並沒有單獨做系統的複習,導致許多關於索引的知識點記憶的很模糊,今天整理下相關筆記(並沒有深挖,對於初學者還是可以看看的),僅供參考。

什麼是索引

  資料庫索引好比是一本書前面的目錄,能加快資料庫的查詢速度。

例如這樣一個查詢:select * from table1 where id=44。如果沒有索引,必須遍歷整個表,直到ID等於44的這一行被找到為止;有了索引之後(必須是在ID這一列上建立的索引),直接在索引裡面找 44(也就是在ID這一列找),就可以得知這一行的位置,也就是找到了這一行。可見,索引是用來定位的。

索引分為聚簇索引和非聚簇索引兩種,聚簇索引 是按照數據存放的物理位置為順序的,而非聚簇索引就不一樣了;聚簇索引能提高多行檢索的速度,而非聚簇索引對於單行的檢索很快。

  建立索引的目的是加快對錶中記錄的查找或排序。

  為表設置索引要付出代價的:一是增加了資料庫的存儲空間,二是在插入和修改數據時要花費較多的時間(因為索引也要隨之變動)。

為什麼要創建索引

創建索引可以大大提高系統的性能。

第一,通過創建唯一性索引,可以保證資料庫表中每一行數據的唯一性。

第二,可以大大加快數據的檢索速度,這也是創建索引的最主要的原因。

第三,可以加速表和表之間的連接,特別是在實現數據的參考完整性方面特別有意義。

第四,在使用分組和排序子句進行數據檢索時,同樣可以顯著減少查詢中分組和排序的時間。

第五,通過使用索引,可以在查詢的過程中,使用優化隱藏器,提高系統的性能。

也許會有人要問:增加索引有如此多的優點,為什麼不對錶中的每一個列創建一個索引呢?因為,增加索引也有許多不利的方面。

第一,創建索引和維護索引要耗費時間,這種時間隨著數據量的增加而增加。

第二,索引需要占物理空間,除了數據表占數據空間之外,每一個索引還要占一定的物理空間,如果要建立聚簇索引,那麼需要的空間就會更大。

第三,當對錶中的數據進行增加、刪除和修改的時候,索引也要動態的維護,這樣就降低了數據的維護速度。

在哪建索引

  索引是建立在資料庫表中的某些列的上面。在創建索引的時候,應該考慮在哪些列上可以創建索引,在哪些列上不能創建索引。一般來說,應該在這些列上創建索引:

1.在經常需要搜索的列上,可以加快搜索的速度;

2.在作為主鍵的列上,強制該列的唯一性和組織表中數據的排列結構;

3.在經常用在連接的列上,這些列主要是一些外鍵,可以加快連接的速度;在經常需要根據範圍進行搜索的列上創建索引,因為索引已經排序,其指定的範圍是連續的;

4.在經常需要排序的列上創建索引,因為索引已經排序,這樣查詢可以利用索引的排序,加快排序查詢時間;

5.在經常使用在WHERE子句中的列上面創建索引,加快條件的判斷速度。

同樣,對於有些列不應該創建索引。一般來說,不應該創建索引的的這些列具有下列特點:

第一,對於那些在查詢中很少使用或者參考的列不應該創建索引。這是因為,既然這些列很少使用到,因此有索引或者無索引,並不能提高查詢速度。相反,由於增加了索引,反而降低了系統的維護速度和增大了空間需求。

第二,對於那些只有很少數據值的列也不應該增加索引。這是因為,由於這些列的取值很少,例如人事表的性別列,在查詢的結果中,結果集的數據行占了表中數據行的很大比例,即需要在表中搜索的數據行的比例很大。增加索引,並不能明顯加快檢索速度。

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

第四,當修改性能遠遠大於檢索性能時,不應該創建索引。這是因為,修改性能和檢索性能是互相矛盾的。當增加索引時,會提高檢索性能,但是會降低修改性能。當減少索引時,會提高修改性能,降低檢索性能。因此,當修改操作遠遠多於檢索操作時,不應該創建索引。

索引的數據結構

  B-tree,B是balance,一般用於資料庫的索引。使用B-tree結構可以顯著減少定位記錄時所經歷的中間過程,從而加快存取速度。而B+tree是B-tree的一個變種,大名鼎鼎的MySQL就普遍使用B+tree實現其索引結構。

  插入(insert)操作:插入一個元素時,首先在B-tree中是否存在,如果不存在,即在葉子結點處結束,然後在葉子結點中插入該新的元素,註意:如果葉子結點空間足夠,這裡需要向右移動該葉子結點中大於新插入關鍵字的元素,如果空間滿了以致沒有足夠的空間去添加新的元素,則將該結點進行“分裂”,將一半數量的關鍵字元素分裂到新的其相鄰右結點中,中間關鍵字元素上移到父結點中(當然,如果父結點空間滿了,也同樣需要“分裂”操作),而且當結點中關鍵元素向右移動了,相關的指針也需要向右移。如果在根結點插入新元素,空間滿了,則進行分裂操作,這樣原來的根結點中的中間關鍵字元素向上移動到新的根結點中,因此導致樹的高度增加一層。

  刪除(delete)操作:首先查找B-tree中需刪除的元素,如果該元素在B-tree中存在,則將該元素在其結點中進行刪除,如果刪除該元素後,首先判斷該元素是否有左右孩子結點,如果有,則上移孩子結點中的某相近元素到父節點中,然後是移動之後的情況;如果沒有,直接刪除後,移動之後的情況.。刪除元素,移動相應元素之後,如果某結點中元素數目小於ceil(m/2)-1,則需要看其某相鄰兄弟結點是否豐滿(結點中元素個數大於ceil(m/2)-1),如果豐滿,則向父節點借一個元素來滿足條件;如果其相鄰兄弟都剛脫貧,即借了之後其結點數目小於ceil(m/2)-1,則該結點與其相鄰的某一兄弟結點進行“合併”成一個結點,以此來滿足條件。

下麵結合例子詳細講解mysql中索引的使用

索引是快速搜索的關鍵。MySQL索引的建立對於MySQL的高效運行是很重要的。下麵介紹幾種常見的MySQL索引類型。

在資料庫表中,對欄位建立索引可以大大提高查詢速度。假如我們創建了一個 mytable表:

CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL 
); 我們隨機向裡面插入了10000條記錄,其中有一條:5555, admin。

在查找username="admin"的記錄 SELECT * FROM mytable WHERE 
username='admin';時,如果在username上已經建立了索引,MySQL無須任何掃描,即準確可找到該記錄。相反,MySQL會掃描所有記錄,即要查詢10000條記錄。

索引分單列索引和組合索引。單列索引,即一個索引只包含單個列,一個表可以有多個單列索引,但這不是組合索引。組合索引,即一個索包含多個列。

MySQL索引類型包括:

(1)普通索引

這是最基本的索引,它沒有任何限制。它有以下幾種創建方式:

◆創建索引

CREATE INDEX indexName ON mytable(username(length)); 
如果是CHAR,VARCHAR類型,length可以小於欄位實際長度;如果是BLOB和TEXT類型,必須指定 length,下同。

◆修改表結構

ALTER mytable ADD INDEX [indexName] ON (username(length))

◆創建表的時候直接指定

CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, 
INDEX [indexName] (username(length)) ); 刪除索引的語法:

DROP INDEX [indexName] ON mytable;

(2)唯一索引

它與前面的普通索引類似,不同的就是:索引列的值必須唯一,但允許有空值。如果是組合索引,則列值的組合必須唯一。它有以下幾種創建方式:

◆創建索引

CREATE UNIQUE INDEX indexName ON mytable(username(length))

◆修改表結構

ALTER mytable ADD UNIQUE [indexName] ON (username(length))

◆創建表的時候直接指定

CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, 
UNIQUE [indexName] (username(length)) ); 

(3)主鍵索引

它是一種特殊的唯一索引,不允許有空值。一般是在建表的時候同時創建主鍵索引:

CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, 
PRIMARY KEY(ID) ); 當然也可以用 ALTER 命令。記住:一個表只能有一個主鍵。

(4)組合索引

為了形象地對比單列索引和組合索引,為表添加多個欄位:

CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, 
city VARCHAR(50) NOT NULL, age INT NOT NULL ); 
為了進一步榨取MySQL的效率,就要考慮建立組合索引。就是將 name, city, age建到一個索引里:

ALTER TABLE mytable ADD INDEX name_city_age (name(10),city,age); 
建表時,usernname長度為 16,這裡用 
10。這是因為一般情況下名字的長度不會超過10,這樣會加速索引查詢速度,還會減少索引文件的大小,提高INSERT的更新速度。

如果分別在 
usernname,city,age上建立單列索引,讓該表有3個單列索引,查詢時和上述的組合索引效率也會大不一樣,遠遠低於我們的組合索引。雖然此時有了三個索引,但MySQL只能用到其中的那個它認為似乎是最有效率的單列索引。

建立這樣的組合索引,其實是相當於分別建立了下麵三組組合索引:

usernname,city,age usernname,city usernname 為什麼沒有 
city,age這樣的組合索引呢?這是因為MySQL組合索引“最左首碼”的結果。簡單的理解就是只從最左面的開始組合。並不是只要包含這三列的查詢都會用到該組合索引,下麵的幾個SQL就會用到這個組合索引:

SELECT * FROM mytable WHREE username="admin" AND city="鄭州" SELECT * FROM 
mytable WHREE username="admin" 而下麵幾個則不會用到:

SELECT * FROM mytable WHREE age=20 AND city="鄭州" SELECT * FROM mytable WHREE 
city="鄭州"

(5)建立索引的時機

到這裡我們已經學會了建立索引,那麼我們需要在什麼情況下建立索引呢?一般來說,在WHERE和JOIN中出現的列需要建立索引,但也不完全如此,因為MySQL只對<,<=,=,>,>=,BETWEEN,IN,以及某些時候的LIKE才會使用索引。例如:

SELECT t.Name FROM mytable t LEFT JOIN mytable m ON t.Name=m.username 
WHERE m.age=20 AND m.city='鄭州' 
此時就需要對city和age建立索引,由於mytable表的userame也出現在了JOIN子句中,也有對它建立索引的必要。

剛纔提到只有某些時候的LIKE才需建立索引。因為在以通配符%和_開頭作查詢時,MySQL不會使用索引。例如下句會使用索引:

SELECT * FROM mytable WHERE username like'admin%' 而下句就不會使用:

SELECT * FROM mytable WHEREt Name like'%admin' 因此,在使用LIKE時應註意以上的區別。

(6)索引的不足之處

上面都在說使用索引的好處,但過多的使用索引將會造成濫用。因此索引也會有它的缺點:

◆雖然索引大大提高了查詢速度,同時卻會降低更新表的速度,如對錶進行INSERT、UPDATE和DELETE。因為更新表時,MySQL不僅要保存數據,還要保存一下索引文件。

◆建立索引會占用磁碟空間的索引文件。一般情況這個問題不太嚴重,但如果你在一個大表上創建了多種組合索引,索引文件的會膨脹很快。

索引只是提高效率的一個因素,如果你的MySQL有大數據量的表,就需要花時間研究建立最優秀的索引,或優化查詢語句。

(7)使用索引的註意事項

使用索引時,有以下一些技巧和註意事項:

◆索引不會包含有NULL值的列

只要列中包含有NULL值都將不會被包含在索引中,複合索引中只要有一列含有NULL值,那麼這一列對於此複合索引就是無效的。所以我們在資料庫設計時不要讓欄位的預設值為NULL。

◆使用短索引

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

◆索引列排序

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

◆like語句操作

一般情況下不鼓勵使用like操作,如果非使用不可,如何使用也是一個問題。like “%aaa%” 不會使用索引而like 
“aaa%”可以使用索引。

◆不要在列上進行運算

select * from users where YEAR(adddate)<2007; 
將在每個行上進行運算,這將導致索引失效而進行全表掃描,因此我們可以改成

select * from users where adddate<‘2007-01-01’; 

◆不使用NOT IN和<>操作

以上,就對其中MySQL索引類型進行了介紹。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 《SQL學習指南》中的第10章 1.4 外連接 在多表連接中,存在連接條件可能無法表中所有的行匹配的問題,例如當account表與customer表進行連接時,會存在account表中cust_id列值無法匹配customer表中的cust_id列值,內連接在無法匹配成功時,是不會將這條匹配失敗的結 ...
  • 函數索引 1.1 概述 在實際應用中,當條件列使用函數運算進行數據匹配時,即使該列建立了索引,索引也不會被使用。 如下示例,其中在owner列上建立一個普通b-tree索引,觀察兩種查詢方式(不使用UPPER函數及使用UPPER函數)的執行計劃的區別。 通過上面的示例可以看到,即使條件列建立了索引, ...
  • 由於項目需要MongoDB做為存儲資料庫,在學習過程碰上疑難雜症,心痛如海,故此終於開始書寫博客之路。 操作MongoDB類庫版本: 連接字元串的相關變化: 沒有安全認證的URL:mongodb://127.0.0.1:27017 加上安全認證的URL:mongodb://[userName]:[u ...
  • 現在MyBatis越來越受大家的喜愛了,它的優勢大家都知道,我就不多說了,直接說重點。 MyBatis中提供動態SQL功能,我們可以使用<if><when><where><otherwise><foreach>等等,這樣我們就可以寫出根據條件生成的動態SQL了,但是,在這中間,我們經常用到的<if> ...
  • 才參加工作不久,很多代碼習慣還沒養成,昨天按要求寫的資料庫基本增刪改查操作,在使用這些方法的時候,雖然能實現功能,但是效率低下,還可能產生記憶體問題,今天被項目經理一頓教育,在此記錄學到的教訓。 mybatis中重覆的代碼使用sql和include標簽進行封裝和調用 資料庫操作使用的是mybatis框 ...
  • 在進行ETL開發時,數據類型(Data Type)是最基礎的,但也容易被忽略,樓主使用的SQL Server 版本是2012,用此博文記錄,常用的SSIS數據類型和TSQL數據類型的映射關係。SSIS的數據類型,主要是指數據流(Data Flow)數據類型和變數(Variable)數據類型。 當數據 ...
  • 無意睹到一篇舊文檔 SR0008:考慮使用 SCOPE_IDENTITY 代替 @@IDENTITY :https://msdn.microsoft.com/zh-cn/library/dd172121(v=vs.100).aspx 日常開發,我們如果在插入記錄的同時需要返回插入的IdentityI ...
  • 如果你初識MySql的話,那麼這些語法糖你有必要知道。 1.Sql創建資料庫 2.Sql創建數據表 3.創建存儲過程 4.關於批量更新和插入數據到mysql ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...