1、索引
簡單的說,索引就像書本的目錄,目錄可以快速找到所在頁數,數據庫中索引可以幫助快速找到數據,而不用全表掃描,合適的索引可以大大提高數據庫查詢的效率。
(1). 優點
大大加快了數據庫檢索的速度,包括對單表查詢、連表查詢、分組查詢、排序查詢。經常是一到兩個數量級的性能提升,且隨着數據數量級增長。
(2). 缺點
索引的創建和維護存在消耗,索引會占用物理空間,且隨着數據量的增加而增加。
在對數據庫進行增刪改時需要維護索引,所以會對增刪改的性能存在影響。
a. 直接創建索引和間接創建索引
直接創建: 使用sql語句創建,Android中可以在SQLiteOpenHelper的onCreate或是onUpgrade中直接excuSql創建語句,語句如
間接創建: 定義主鍵約束或者唯一性鍵約束,可以間接創建索引,主鍵默認為唯一索引。
b. 普通索引和唯一性索引
普通索引:
唯一性索引:保證在索引列中的全部數據是唯一的,對聚簇索引和非聚簇索引都可以使用,語句為
c. 單個索引和復合索引
單個索引:索引建立語句中僅包含單個字段,如上面的普通索引和唯一性索引創建示例。
復合索引:又叫組合索引,在索引建立語句中同時包含多個字段,語句如:
CREATE INDEX name_index ON username(firstname, lastname)
其中firstname為前導列。
d. 聚簇索引和非聚簇索引(聚集索引,群集索引)
聚簇索引:物理索引,與基表的物理順序相同,數據值的順序總是按照順序排列,語句為:
其中WITH ALLOW_DUP_ROW表示允許有重復記錄的聚簇索引
非聚簇索引:
索引默認為非聚簇索引
(4). 使用場景
在上面講到了優缺點,那么肯定會對何時使用索引既有點明白又有點糊塗吧,那么下面總結下:
a. 當某字段數據更新頻率較低,查詢頻率較高,經常有范圍查詢(>, <, =, >=, <=)或order by、group by發生時建議使用索引。並且選擇度越大,建索引越有優勢,這里選擇度指一個字段中唯一值的數量/總的數量。
b. 經常同時存取多列,且每列都含有重復值可考慮建立復合索引
、查看數據庫表中索引的情況
select i.name AS '索引名稱' ,o.name AS TableName,avg_fragmentation_in_percent,*
FROM sys.dm_db_index_physical_stats(DB_ID() ,object_id('agent') ,NULL,NULL,NULL)
inner join sys.indexes i on i.object_id=dm_db_index_physical_stats.object_id
INNER JOIN sys.objects o ON o.object_id = i.object_id
查詢結果重要字段解釋:
| database_id | 表或視圖的數據庫 ID | ||
| TableName | 表名稱 | ||
| index_level | 索引的當前位於B樹結構中的級別。 0 表示索引葉級別、堆以及 LOB_DATA 或 ROW_OVERFLOW_DATA 分配單元。 大於 0 的值表示非葉索引級別。 index_level 在索引的根級別中屬於最高級別。 僅當 mode = DETAILED 時才處理非葉級別的索引。 |
||
| avg_fragmentation_in_percent | 索引的邏輯碎片,或 IN_ROW_DATA 分配單元中堆的區碎片。 此值按百分比計算,並將考慮多個文件。 0 表示 LOB_DATA 和 ROW_OVERFLOW_DATA 分配單元。 如果是堆表且mode模式 為 Sampled 時,為 NULL。如果碎片小於10%~20%,碎片不太可能會成為問題,如果索引碎片在20%~40%,碎片可能成為問題,但是可以通過索引重組來消除索引解決,大規模的碎片(當碎片大於40%),可能要求索引重建。 |
||
| page_count | 索引或數據頁的總數。 對於索引,表示 IN_ROW_DATA 分配單元中 b 樹的當前級別中的索引頁總數。 對於堆,表示 IN_ROW_DATA 分配單元中的數據頁總數。 對於 LOB_DATA 或 ROW_OVERFLOW_DATA 分配單元,表示該分配單元中的總頁數。 |
||
| record_count | 總記錄數。 對於索引,記錄的總數應用於 IN_ROW_DATA 分配單元中 b 樹(包括非葉子數據頁的數量)的當前級別。 對於堆,表示 IN_ROW_DATA 分配單元中的總記錄數。
對於 LOB_DATA 或 ROW_OVERFLOW_DATA 分配單元,表示整個分配單元中總記錄數。 當 mode 為 LIMITED 時,為 NULL。 |
||
| index_id | 索引的索引 ID。 0 = 堆。 |
2、關於碎片的解決方法:
1.刪除索引並重建
這種方式有如下缺點:
索引不可用:在刪除索引期間,索引不可用。
阻塞:卸載並重建索引會阻塞表上所有的其他請求,也可能被其他請求所阻塞。
對於刪除聚集索引,則會導致對應的非聚集索引重建兩次(刪除時重建,建立時再重建,因為非聚集索引中有指向聚集索引的指針)。
唯一性約束:用於定義主鍵或者唯一性約束的索引不能使用DROP INDEX語句刪除。而且,唯一性約束和主鍵都可能被外鍵約束引用。在主鍵卸載之前,所有引用該主鍵的外鍵必須首先被刪除。盡管可以這么做,但這是一種冒險而且費時的碎片整理方法。
基於以上原因,不建議在生產數據庫,尤其是非空閑時間不建議采用這種技術。
2.使用DROP_EXISTING語句重建索引
為了避免重建兩次索引,使用DROP_EXISTING語句重建索引,因為這個語句是原子性的,不會導致非聚集索引重建兩次,但同樣的,這種方式也會造成阻塞。
CREATE UNIQUE CLUSTERED INDEX IX_C1 ON t1(c1) WITH (DROP_EXISTING = ON)
缺點:
阻塞:與卸載重建方法類似,這種技術也導致並面臨來自其他訪問該表(或該表的索引)的查詢的阻塞問題。
使用約束的索引:與卸載重建不同,具有DROP_EXISTING子句的CREATE INDEX語句可以用於重新創建使用約束的索引。如果該約束是一個主鍵或與外鍵相關的唯一性約束,在CREATE語句中不能包含UNIQUE。
具有多個碎片化的索引的表:隨着表數據產生碎片,索引常常也碎片化。如果使用這種碎片整理技術,表上所有索引都必須單獨確認和重建。
3.使用ALTER INDEX REBUILD語句重建索引
使用這個語句同樣也是重建索引,但是通過動態重建索引而不需要卸載並重建索引.是優於前兩種方法的,但依舊會造成阻塞。可以通過ONLINE關鍵字減少鎖,但會造成重建時間加長。
阻塞:這個依然有阻塞問題。
事務回滾:ALTER INDEX REBUILD完全是一個原子操作,如果它在結束前停止,所有到那時為止進行的碎片整理操作都將丟失,可以通過ONLINE關鍵字減少鎖,但會造成重建時間加長。
4.使用ALTER INDEX REORGANIZE
這種方式不會重建索引,也不會生成新的頁,僅僅是整理葉級數據,不涉及非葉級,當遇到加鎖的頁時跳過,所以不會造成阻塞。但同時,整理效果會差於前三種。
4種索引整理技術比較:
| 特性/問題 | 卸載並重建索引 | DROP_EXISTING | ALTER INDEX REBUILD | ALTER INDEX REORGANIZE |
| 在聚集索引碎片整理時,重建非聚集索引 | 兩次 | 無 | 無 | 無 |
| 丟失索引 | 是 | 無 | 無 | 無 |
| 整理具有約束的索引的碎片 | 高度復雜 | 復雜性適中 | 簡單 | 簡單 |
| 同時進行多個索引的碎片整理 | 否 | 否 | 是 | 是 |
| 並發性 | 低 | 低 | 中等,取決於冰法用戶活動 | 高 |
| 中途撤銷 | 因為不使用事務,存在危險 | 進程丟失 | 進程丟失 | 進程被保留 |
| 碎片整理程度 | 高 | 高 | 高 | 中到低 |
| 應用新的填充因子 | 是 | 是 | 是 | 否 |
| 更新統計 | 是 | 是 | 是 | 否 |
