索引是與表或視圖關聯的磁盤上結構,可以加快從表或視圖中檢索行的速度。索引包含由表或視圖中的一列或多列生成的鍵。這些鍵存儲在一個結構(B 樹)中,使 SQL Server 可以快速有效地查找與鍵值關聯的行。
表或視圖可以包含以下類型的索引:
* 聚集
o 聚集索引根據數據行的鍵值在表或視圖中排序和存儲這些數據行。索引定義中包含聚集索引列。每個表只能有一個聚集索引,因為數據行本身只能按一個順序排序。
o 只有當表包含聚集索引時,表中的數據行才按排序順序存儲。如果表具有聚集索引,則該表稱為聚集表。如果表沒有聚集索引,則其數據行存儲在一個稱為堆的無序結構中。
* 非聚集
o 非聚集索引具有獨立於數據行的結構。非聚集索引包含非聚集索引鍵值,並且每個鍵值項都有指向包含該鍵值的數據行的指針。
o 從非聚集索引中的索引行指向數據行的指針稱為行定位器。行定位器的結構取決於數據頁是存儲在堆中還是聚集表中。對於堆,行定位器是指向行的指針。對於聚集表,行定位器是聚集索引鍵。
o 您可以向非聚集索引的葉級添加非鍵列以跳過現有的索引鍵限制(900 字節和 16 鍵列),並執行完整范圍內的索引查詢。
聚集索引和非聚集索引都可以是唯一的。這意味着任何兩行都不能有相同的索引鍵值。另外,索引也可以不是唯一的,即多行可以共享同一鍵值。
每當修改了表數據后,都會自動維護表或視圖的索引。
索引和約束
對表列定義了 PRIMARY KEY 約束和 UNIQUE 約束時,會自動創建索引。例如,如果創建了表並將一個特定列標識為主鍵,則 數據庫引擎自動對該列創建 PRIMARY KEY 約束和索引。有關詳細信息,請參閱創建索引(數據庫引擎)。
二、索引有什么用
與書中的索引一樣,數據庫中的索引使您可以快速找到表或索引視圖中的特定信息。索引包含從表或視圖中一個或多個列生成的鍵,以及映射到指定數據的存儲位置的指針。通過創建設計良好的索引以支持查詢,可以顯著提高數據庫查詢和應用程序的性能。索引可以減少為返回查詢結果集而必須讀取的數據量。索引還可以強制表中的行具有唯一性,從而確保表數據的數據完整性。
設計良好的索引可以減少磁盤 I/O 操作,並且消耗的系統資源也較少,從而可以提高查詢性能。對於包含 SELECT、UPDATE、DELETE 或 MERGE 語句的各種查詢,索引會很有用。例如,在 AdventureWorks 數據庫中執行的查詢 SELECT Title, HireDate FROM HumanResources.Employee WHERE EmployeeID = 250。執行此查詢時,查詢優化器評估可用於檢索數據的每個方法,然后選擇最有效的方法。可能采用的方法包括掃描表和掃描一個或多個索引(如果有)。
掃描表時,查詢優化器讀取表中的所有行,並提取滿足查詢條件的行。掃描表會有許多磁盤 I/O 操作,並占用大量資源。但是,如果查詢的結果集是占表中較高百分比的行,掃描表會是最為有效的方法。
查詢優化器使用索引時,搜索索引鍵列,查找到查詢所需行的存儲位置,然后從該位置提取匹配行。通常,搜索索引比搜索表要快很多,因為索引與表不同,一般每行包含的列非常少,且行遵循排序順序。
查詢優化器在執行查詢時通常會選擇最有效的方法。但如果沒有索引,則查詢優化器必須掃描表。您的任務是設計並創建最適合您的環境的索引,以便查詢優化器可以從多個有效的索引中選擇。SQL Server 提供的數據庫引擎優化顧問可以幫助分析數據庫環境並選擇適當的索引。
三、索引怎么用
索引其實關鍵目的是為了加快檢索速度而建立的,所以,怎么用索引是數據庫系統本身的事情,作為數據庫設計或使用者,設計並創建好索引然后體驗加上索引后的查詢變快的感覺就行了。所以,索引怎么用就變為了“怎么創建合適的索引”,以下說明這個問題:
索引設計不佳和缺少索引是提高數據庫和應用程序性能的主要障礙。設計高效的索引對於獲得良好的數據庫和應用程序性能極為重要。為數據庫及其工作負荷選擇正確的索引是一項需要在查詢速度與更新所需開銷之間取得平衡的復雜任務。如果索引較窄,或者說索引關鍵字中只有很少的幾列,則需要的磁盤空間和維護開銷都較少。而另一方面,寬索引可覆蓋更多的查詢。您可能需要試驗若干不同的設計,才能找到最有效的索引。可以添加、修改和刪除索引而不影響數據庫架構或應用程序設計。因此,應試驗多個不同的索引而無需猶豫。
SQL Server 中的查詢優化器可在大多數情況下可靠地選擇最高效的索引。總體索引設計策略應為查詢優化器提供可供選擇的多個索引,並依賴查詢優化器做出正確的決定。這在多種情況下可減少分析時間並獲得良好的性能。若要查看查詢優化器對特定查詢使用的索引,請在 SQL Server Management Studio 中的“查詢”菜單上選擇“包括實際的執行計划”。
不要總是將索引的使用等同於良好的性能,或者將良好的性能等同於索引的高效使用。如果只要使用索引就能獲得最佳性能,那查詢優化器的工作就簡單了。但事實上,不正確的索引選擇並不能獲得最佳性能。因此,查詢優化器的任務是只在索引或索引組合能提高性能時才選擇它,而在索引檢索有礙性能時則避免使用它。
建議的索引設計策略包括以下任務:
1. 了解數據庫本身的特征。例如,它是頻繁修改數據的聯機事務處理 (OLTP) 數據庫,還是主要包含只讀數據的決策支持系統 (DSS) 或數據倉庫 (OLAP) 數據庫?
2. 了解最常用的查詢的特征。例如,了解到最常用的查詢聯接兩個或多個表將有助於決定要使用的最佳索引類型。
3. 了解查詢中使用的列的特征。例如,某個索引對於含有整數數據類型同時還是唯一的或非空的列是理想索引。篩選索引適用於具有定義完善的數據子集的列。
4. 確定哪些索引選項可在創建或維護索引時提高性能。例如,對現有某個大型表創建聚集索引將會受益於 ONLINE 索引選項。ONLINE 選項允許在創建索引或重新生成索引時繼續對基礎數據執行並發活動。
5. 確定索引的最佳存儲位置。非聚集索引可以與基礎表存儲在同一個文件組中,也可以存儲在不同的文件組中。索引的存儲位置可通過提高磁盤 I/O 性能來提高查詢性能。例如,將非聚集索引存儲在表文件組所在磁盤以外的某個磁盤上的一個文件組中可以提高性能,因為可以同時讀取多個磁盤。
或者,聚集索引和非聚集索引也可以使用跨越多個文件組的分區方案。在維護整個集合的完整性時,使用分區可以快速而有效地訪問或管理數據子集,從而使大型表或索引更易於管理。有關詳細信息,請參閱已分區表和已分區索引。在考慮分區時,應確定是否應對齊索引,即,是按實質上與表相同的方式進行分區,還是單獨分區。
# 設計索引。
索引設計是一項關鍵任務。索引設計包括確定要使用的列,選擇索引類型(例如聚集或非聚集),選擇適當的索引選項,以及確定文件組或分區方案布置。
# 確定最佳的創建方法。按照以下方法創建索引:
* 使用 CREATE TABLE 或 ALTER TABLE 對列定義 PRIMARY KEY 或 UNIQUE 約束
SQL Server 數據庫引擎自動創建唯一索引來強制 PRIMARY KEY 或 UNIQUE 約束的唯一性要求。默認情況下,創建的唯一聚集索引可以強制 PRIMARY KEY 約束,除非表中已存在聚集索引或指定了唯一的非聚集索引。默認情況下,創建的唯一非聚集索引可以強制 UNIQUE 約束,除非已明確指定唯一的聚集索引且表中不存在聚集索引。
還可以指定索引選項和索引位置、文件組或分區方案。
創建為 PRIMARY KEY 或 UNIQUE 約束的一部分的索引將自動給定與約束名稱相同的名稱。
* 使用 CREATE INDEX 語句或 SQL Server Management Studio 對象資源管理器中的“新建索引”對話框創建獨立於約束的索引
必須指定索引的名稱、表以及應用該索引的列。還可以指定索引選項和索引位置、文件組或分區方案。默認情況下,如果未指定聚集或唯一選項,將創建非聚集的非唯一索引。若要創建篩選索引,請使用可選的 WHERE 子句。
# 創建索引。
要考慮的一個重要因素是對空表還是對包含數據的表創建索引。對空表創建索引在創建索引時不會對性能產生任何影響,而向表中添加數據時,會對性能產生影響。
對大型表創建索引時應仔細計划,這樣才不會影響數據庫性能。對大型表創建索引的首選方法是先創建聚集索引,然后創建任何非聚集索引。在對現有表創建索引時,請考慮將 ONLINE 選項設置為 ON。該選項設置為 ON 時,將不持有長期表鎖以繼續對基礎表的查詢或更新。
簡單的創建索引,可采用如下語句:
CREATE INDEX IX_ProductVendor_VendorID
ON Purchasing.ProductVendor (VendorID, VendorName);
GO
索引用於快速找出在某個列中有一特定值的行。不使用索引,MySQL必須從第1條記錄開始然后讀完整個表直到找出相關的行。
表越大,花費的時間越多。如果表中查詢的列有一個索引,MySQL能快速到達一個位置去搜尋到數據文件的中間,沒有必要看所有數據。
大多數MySQL索引(PRIMARY KEY、UNIQUE、INDEX和FULLTEXT)在B樹中存儲。只是空間列類型的索引使用R-樹,並且MEMORY表還支持hash索引
大多數情況下索引能大幅度提高查詢效率,但:
- 數據的變更(增刪改)都需要維護索引,因此更多的索引意味着更多的維護成本
- 更多的索引意味着也需要更多的空間 (一本100頁的書,卻有50頁目錄?)
- 過小的表,建索引可能會更慢哦 :) (讀個2頁的宣傳手冊,你還先去找目錄?)
索引的字段類型問題
- text類型,也可建索引(需指定長度)
- myisam存儲引擎索引鍵長度綜合不能超過1000字節
- 用來篩選的值盡量保持和索引列同樣的數據類型
like 不能用索引?
-
盡量減少like,但不是絕對不可用,”xxxx%” 是可以用到索引的,
想象一下,你在看一本成語詞典,目錄是按成語拼音順序建立,查詢需求是,你想找以 “一”字開頭的成語(”一%“),和你想找包含一字的成語(“%一%”)
-
除了like,以下操作符也可用到索引:
<,<=,=,>,>=,BETWEEN,IN
<>,not in ,!=則不行
什么樣的字段不適合建索引?
一般來說,列的值唯一性太小(如性別,類型什么的),不適合建索引(怎樣叫太小?一半說來,同值的數據超過表的百分之15,那就沒必要建索引了)
太長的列,可以選擇只建立部分索引,(如:只取前十位做索引)
更新非常頻繁的數據不適宜建索引(怎樣叫非常?意會)
一次查詢能用多個索引嗎?
不能
多列查詢該如何建索引?
一次查詢只能用到一個索引,所以 首先槍斃 a,b各建索引方案
a還是b? 誰的區分度更高(同值的最少),建誰!
當然,聯合索引也是個不錯的方案,ab,還是ba,則同上,區分度高者,在前
聯合索引的問題?
where a = “xxx” 可以使用 AB 聯合索引
where b = “xxx” 則不可 (再想象一下,這是書的目錄?)
所以,大多數情況下,有AB索引了,就可以不用在去建一個A索引了
哪些常見情況不能用索引?
like “%xxx”
not in , !=
對列進行函數運算的情況(如 where md5(password) = “xxxx”)
WHERE index=1 OR A=10
存了數值的字符串類型字段(如手機號),查詢時記得不要丟掉值的引號,否則無法用到該字段相關索引,反之則沒關系
也即
select * from test where mobile = 13711112222;
可是無法用到mobile字段的索引的哦(如果mobile是char 或 varchar類型的話)
btw,千萬不要嘗試用int來存手機號(為什么?自己想!要不自己試試)
覆蓋索引(Covering Indexes)擁有更高效率
索引包含了所需的全部值的話,就只select 他們,換言之,只select 需要用到的字段,如無必要,可盡量避免select *
NULL 的問題
NULL會導致索引形同虛設,所以在設計表結構時應避免NULL 的存在(用其他方式表達你想表達的NULL,比如 -1?)
如何查看索引信息,如何分析是否正確用到索引?
show index from tablename;
explain select ……;
1.創建表並插入數據
在Sql Server2008中創建測試數據庫Test,接着創建數據庫表並插入數據,sql代碼如下:
USE Test IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'emp_pay') DROP TABLE emp_pay GO USE Test IF EXISTS (SELECT name FROM sys.indexes WHERE name = 'employeeID_ind') DROP INDEX emp_pay.employeeID_ind GO USE Test GO CREATE TABLE emp_pay ( employeeID int NOT NULL, base_pay money NOT NULL, commission decimal(2, 2) NOT NULL ) INSERT emp_pay VALUES (1, 500, .10) INSERT emp_pay VALUES (2, 1000, .05) INSERT emp_pay VALUES (6, 800, .07) INSERT emp_pay VALUES (5, 1500, .03) INSERT emp_pay VALUES (9, 750, .06)
執行完上述sql代碼以后我們會發現在Test數據庫中多出了一張emp_pay表,數據庫表的內容如下圖所示:
2.無索引查找
從上圖我們可以看出數據庫中存儲的數據排列順序與我們插入的先后順序一致。接下來我們查詢employeeID=5的字段,執行如下sql代碼:
USE Test SELECT * FROM emp_pay where employeeID=5
在SQL SERVER MANAGEMENT STUDIO中我們點擊“顯示估計的查詢計划”,會出現如下圖所示的查詢計划圖:
其中表掃描的內容為:
3.創建索引
接下來我們為上述表添加聚集唯一索引,代碼如下:
SET NOCOUNT OFF CREATE UNIQUE CLUSTERED INDEX employeeID_ind ON emp_pay (employeeID) GO
在執行完上述創建索引的代碼以后,我們再次查詢emp_pay的數據內容,如下圖所示:
從上圖我們可以發現數據內容已經按照employeeID進行了排序。
我們繼續執行前面關於employeeID=5的查詢,點擊“顯示估計的執行計划”,出現如下圖所示內容:
聚集索引查找的內容為:
總結:
當我們為數據庫表中的某一個字段創建索引,並且在查詢語句中where子句中用到這樣一個字段,那么查詢效率會有所提高,我們上述實驗因為數據量的關系查詢效率提高不明顯。
補充
我們上面添加的索引是唯一聚集索引,因此當插入的數據在employeeID字段出現重復時會報錯。假如我們在創建索引之前數據字段出現重復,那么就不能創建唯一索引。
創建索引以后的排序(PS:2012-5-28)
執行如下sql語句
update emp_pay set employeeID=7 where employeeID=1;
然后再次執行全表查詢,我們發現查詢結果如下所示:
只要我們更新了employeeID,那么最后的更新結果都會按照employeeID的值進行升序排序。這是因為我們在employeeID上創建了索引的緣故。
刪除索引(PS:2012-6-4)
我們可以通過sql server management studio這個工具刪除索引,也可以通過sql語句進行索引的刪除,假設我們要求刪除在前面創建的索引employeeID_ind,那么sql語句如下代碼所示:
DROP INDEX employeeID_ind ON emp_pay;