1. 程式人生 > >數據庫索引優化原理,索引的工作機制

數據庫索引優化原理,索引的工作機制

更新 重點 黃金 在一起 view gen 一點 lan 成了

我們通過一個簡單的例子來開始教程,解釋為什麽我們需要數據庫索引。假設我們有一個數據庫表 Employee, 這個表有三個字段(列)分別是 Employee_Name、Employee_Age 和Employee_Address。假設表Employee 有上千行數據。

現在假設我們要從這個表中查找出所有名字是‘Jesus’的雇員信息。我們決定使用下面的查詢語句:

SELECT * FROM Employee 
WHERE Employee_Name = ‘Jesus‘

如果表中沒有所以會發生什麽?

一旦我們運行這個查詢,在查找名字為Jesus的雇員的過程中,究竟會發生什麽?數據庫不得不Employee表中的每一行並確定雇員的名字(Employee_Name)是否為 ‘Jesus’。由於我們想要得到每一個名字為Jesus的雇員信息,在查詢到第一個符合條件的行後,不能停止查詢,因為可能還有其他符合條件的行。所以,必須一行一行的查找直到最後一行-這就意味數據庫不得不檢查上千行數據才能找到所以名字為Jesus的雇員。這就是所謂的全表掃描

數據庫索引是怎樣提升性能的?

你可能會想為如此簡單的事情做全表掃描效率欠佳-數據庫是不是應該更聰明一點呢?這就像用人眼從頭到尾瀏覽整張表-很慢也不優雅(原文:not at all sleek,不知如何翻譯才好)。但是,你可以能根據文章標題已經猜到,這就是索引派上用場的時候。使用索引的全部意義就是通過縮小一張表中需要查詢的記錄/行的數目來加快搜索的速度

什麽是索引?

一個索引是存儲的表中一個特定列的值數據結構(最常見的是B-Tree)。索引是在表的列上創建。所以,要記住的關鍵點是索引包含一個表中列的值,並且這些值存儲在一個數據結構中。請記住記住這一點:索引是一種數據結構 。

什麽樣的數據結構可以作為索引?

B-Tree 是最常用的用於索引的數據結構。因為它們是時間復雜度低, 查找、刪除、插入操作都可以可以在對數時間內完成。另外一個重要原因存儲在B-Tree中的數據是有序的。數據庫管理系統(RDBMS)通常決定索引應該用哪些數據結構。但是,在某些情況下,你在創建索引時可以指定索引要使用的數據結構。

哈希表索引是怎麽工作的?

哈希表是另外一種你可能看到用作索引的數據結構-這些索引通常被稱為哈希索引。使用哈希索引的原因是,在尋找值時哈希表效率極高。所以,如果使用哈希索引,對於比較字符串是否相等的查詢能夠極快的檢索出的值。例如之前我們討論過的這個查詢(SELECT * FROM Employee WHERE Employee_Name = ‘Jesus’) 就可以受益於創建在Employee_Name 列上的哈希索引。哈系索引的工作方式是將列的值作為索引的鍵值(key),和鍵值相對應實際的值(value)是指向該表中相應行的指針。因為哈希表基本上可以看作是關聯數組,一個典型的數據項就像“Jesus => 0x28939″,而0x28939是對內存中表中包含Jesus這一行的引用。在哈系索引的中查詢一個像“Jesus”這樣的值,並得到對應行的在內存中的引用,明顯要比掃描全表獲得值為“Jesus”的行的方式快很多。

哈希索引的缺點

哈希表是無順的數據結構,對於很多類型的查詢語句哈希索引都無能為力。舉例來說,假如你想要找出所有小於40歲的員工。你怎麽使用使用哈希索引進行查詢?這不可行,因為哈希表只適合查詢鍵值對-也就是說查詢相等的查詢(例:like “WHERE name = ‘Jesus’)。哈希表的鍵值映射也暗示其鍵的存儲是無序的。這就是為什麽哈希索引通常不是數據庫索引的默認數據結構-因為在作為索引的數據結構時,其不像B-Tree那麽靈活

還有什麽其他類型的索引?

使用R-Tree作為數據結構的索引通常用來為空間問題提供幫助。例如,一個查詢要求“查詢出所有距離我兩公裏之內的星巴克”,如果數據庫表使用R- Tree索引,這類查詢的效率將會提高。
另一種索引是位圖索引(bitmap index), 這類索引適合放在包含布爾值(true 和 false)的列上,但是這些值(表示true或false的值)的許多實例-基本上都是選擇性(selectivity)低的列。

索引是怎麽提升性能的?

因為索引基本上是用來存儲列值的數據結構,這使查找這些列值更加快速。如果索引使用最常用的數據結構-B-Tree-那麽其中的數據是有序的。有序的列值可以極大的提升性能。下面解釋原因。

假設我們在 Employee_Name這一列上創建一個B-Tree索引。這意味著當我們用之前的SQL查找姓名是‘Jesus’的雇員時,不需要再掃描全表。而是用索引查找去查找名字為‘Jesus’的雇員,因為索引已經按照按字母順序排序。索引已經排序意味著查詢一個名字會快很多,因為名字少字母為‘J’的員工都是排列在一起的。另外重要的一點是,索引同時存儲了表中相應行的指針以獲取其他列的數據。

數據庫索引裏究竟存的是什麽?

你現在已經知道數據庫索引是創建在表的某列上的,並且存儲了這一列的所有值。但是,需要理解的重點是數據庫索引並不存儲這個表中其他列(字段)的值。舉例來說,如果我們在Employee_Name列創建索引,那麽列Employee_Age和Employee_Address上的值並不會存儲在這個索引當中。如果我們確實把其他所有字段也存儲在個這個索引中,那就成了拷貝一整張表做為索引-這樣會占用太大的空間而且會十分低效。

索引存儲了指向表中某一行的指針

如果我們在索引裏找到某一條記錄作為索引的列的值,如何才能找到這一條記錄的其它值呢?這是很簡單 - 數據庫索引同時存儲了指向表中的相應行的指針。指針是指一塊內存區域, 該內存區域記錄的是對硬盤上記錄的相應行的數據的引用。因此,索引中除了存儲列的值,還存儲著一個指向在行數據的索引。也就是說,索引中的Employee_Name這列的某個值(或者節點)可以描述為 (“Jesus”, 0x82829), 0x82829 就是包含 “Jesus”那行數據在硬盤上的地址。如果沒有這個引用,你就只能訪問到一個單獨的值(“Jesus”),而這樣沒有意義,因為你不能獲取這一行記錄的employee的其他值-例如地址(address)和年齡(age)。

數據庫怎麽知道什麽時候使用索引?

當這個SQL (SELECT * FROM Employee WHERE Employee_Name = ‘Jesus’ )運行時,數據庫會檢查在查詢的列上是否有索引。假設Employee_Name列上確實創建了索引,數據庫會接著檢查使用這個索引做查詢是否合理 - 因為有些場景下,使用索引比起全表掃描會更加低效。如果想要了解更多這些場景,請閱讀這篇文章:Selectivity in SQL

你能強制數據庫使用索引嗎?

通常來說, 你不會告訴數據庫什麽時候使用索引 - 數據庫自己決定。然而,值得註意的是在大多數數據庫中(像Oracle 和 MYSQL), 你實際上可以制訂你想要使用的索引。

如何在使用SQL創建索引:

之前的例子中,在Employee_Name列上創建索引的SQL如下:

CREATE INDEX name_index
ON Employee (Employee_Name)

如何創建聯合索引

我們可以在雇員表上創建兩個列的聯合索引,SQL如下:

CREATE INDEX name_index
ON Employee (Employee_Name, Employee_Age)

把數據庫索引類比成什麽比較好呢?

一個非常好的類比是把數據庫索引看作是書的索引。如果你有一本關於狗的書,你想要找關於‘黃金獵犬’的那部分。當你可以通過在書背的索引找到哪幾頁有關於‘黃金獵犬’信息的時候,你為什麽要翻完正本書 - 這相當於數據庫中的全表掃描。同樣的,就像一本書的索引包含頁碼一樣,數據庫的索引包含了指針,指向你在SQL中想要查詢的值所在的行。

使用數據庫索引會有什麽代價?

那麽,使用數據庫索引有什麽缺點呢?其一,索引會占用空間 - 你的表越大,索引占用的空間越大。其二,性能損失(主要值更新操作),當你在表中添加、刪除或者更新行數據的時候, 在索引中也會有相同的操作。記住:建立在某列(或多列)索引需要保存該列最新的數據

基本原則是只如果表中某列在查詢過程中使用的非常頻繁,那就在該列上創建索引

原文鏈接:

http://www.programmerinterview.com/index.php/database-sql/what-is-an-index/

想要了解更多索引相關的知識,請參考一下鏈接:
http://www.programmerinterview.com/index.php/database-sql/what-is-an-index/
http://www.programmerinterview.com/index.php/database-sql/selectivity-in-sql-databases/
http://www.programmerinterview.com/index.php/database-sql/cardinality-in-sql/
http://use-the-index-luke.com/sql/preface#

數據庫索引優化原理,索引的工作機制