寫這篇文章幫助自己更好的理解索引,也算是自己的學(xué)習(xí)筆記吧,分享給大家 ,文中如果有分析的不正確的地方,歡迎指出 。
一. 聚集索引B樹分析
1.聚集索引按B樹結(jié)構(gòu)進(jìn)行組織的,索引B樹種的每一頁稱為一個(gè)索引節(jié)點(diǎn)。B樹的頂端節(jié)點(diǎn)稱為根節(jié)點(diǎn)。
索引中的低層節(jié)點(diǎn)稱為葉節(jié)點(diǎn)。根節(jié)點(diǎn)與葉節(jié)點(diǎn)之間的任何索引級別統(tǒng)稱為中間級。在聚集索引中,葉節(jié)點(diǎn)包含基礎(chǔ)表的數(shù)據(jù)頁。
根節(jié)點(diǎn)和中間級節(jié)點(diǎn)包含存有索引行的索引頁。每個(gè)索引行包含一個(gè)鍵值和一個(gè)指針,該指針指向 B 樹上的某一中間級頁或葉級索引中的某個(gè)數(shù)據(jù)行.每級索引中的頁均被連接在雙向鏈接列表中。
2.索引使用的每一個(gè)分區(qū)的index_id = 1 ,默認(rèn)情況下聚集索引單個(gè)分區(qū),當(dāng)使用分區(qū)表的時(shí)候,每個(gè)分區(qū)都有一個(gè)包含該特定分區(qū)相關(guān)數(shù)據(jù)的B樹結(jié)構(gòu),我是這么理解的不知道對不對?
3.SQL Server 寫入的數(shù)據(jù),數(shù)據(jù)鏈內(nèi)的頁和行將按聚集索引鍵值進(jìn)行排序。
4.SQL Server 將在索引中查找該范圍的起始鍵值,然后用向前或向后在數(shù)據(jù)頁中進(jìn)行掃描。為了查找數(shù)據(jù)頁鏈的首頁,SQL Server 將從索引的根節(jié)點(diǎn)沿最左邊的指針進(jìn)行掃描。
聚集索引B樹圖 :
二 .優(yōu)化 Transact-SQL 語句經(jīng)常使用的語句
1.SET STATISTICS IO {ON| OFF} /*Transact-SQL 語句生成的磁盤活動量的信息*/
2.SET SHOWPLAN_ALL ON {ON| OFF} /*返回有關(guān)語句執(zhí)行情況的詳細(xì)信息,并估計(jì)語句對資源的需求*/
3.SET STATISTICS TIME {ON| OFF} /*顯示分析、編譯和執(zhí)行各語句所需的毫秒數(shù)*/
4.使用T-SQL語句創(chuàng)建索引的語法:
CREATE [UNIQUE] [CLUSTERED|NONCLUSTERED]
INDEX index_name
ON table_name (column_name)
[WITH FILLFACTOR=x]
UNIQUE表示唯一索引,可選CLUSTERED、NONCLUSTERED表示聚集索引還是非聚集索引, 可選 FILLFACTOR表示填充因子,指定一個(gè)0到100之間的值,該值指示索引頁填滿的空間所占的百分比
SET STATISTICS IO 輸出信息如圖
三 創(chuàng)建數(shù)據(jù)測試下上面學(xué)到的理論知識
--創(chuàng)建表
CREATE TABLE employee
(
emp_username varchar (20),
emp_register DATETIME
)
--插入測試數(shù)據(jù)
DECLARE @startid INT
DECLARE @endid INT
SELECT @startid= 1,@endid = 100
WHILE @startid <=@endid
BEGIN
INSERT INTO employee (
emp_username,
emp_register
) VALUES (
/* emp_username - varchar (20) */ '劉'+CAST(@startid AS NVARCHAR(20)),
/* emp_register - DATETIME */ GETDATE() )
SELECT @startid =@startid +1;
END
-- 查詢employee的執(zhí)行計(jì)劃 和 io 信息
SET STATISTICS IO ON
SELECT * FROM employee WHERE emp_username = '劉'
查看消息輸出的 IO 信息
表'employee'。(1)1掃描計(jì)數(shù)1,(2)邏輯讀取1 次,(3)物理讀取0 次,(4)預(yù)讀0 次,lob 邏輯讀取0 次,lob 物理讀取0 次,lob 預(yù)讀0 次。
輸出的信息和上面的圖片講解的是對應(yīng)的
1. 執(zhí)行的掃描次數(shù) 。
2. 從磁盤讀取的頁數(shù)。
3. 為進(jìn)行查詢而放入緩存的頁數(shù)。
4. 預(yù)讀
T_SQL transaction 語句有很多種的寫法,但是決定那條語句是最優(yōu)的是根據(jù)(logical reads) 邏輯讀取來判斷。
添加聚集索引 查詢邏輯讀取是否會變少
CREATE CLUSTERED INDEX Idx_emp_username ON employee (emp_username);
--然后再執(zhí)行查詢
SET STATISTICS IO ON
SELECT * FROM employee WHERE emp_username = '劉'
查看消息輸出的 IO 信息
表'employee'。掃描計(jì)數(shù)1,邏輯讀取2 次,物理讀取0 次,預(yù)讀0 次,lob 邏輯讀取0 次,lob 物理讀取0 次,lob 預(yù)讀0 次。
Q 這次邏輯讀取是2次為什么呢 ?
A.難道查詢比表掃描還要慢,答案是對的,數(shù)據(jù)量小的時(shí)候,聚集索引的優(yōu)勢體現(xiàn)不出來。
Q 為什么是2次邏輯讀取
A 現(xiàn)在查詢的時(shí)候如聚集索引圖,先查詢索引頁 ,查找到對應(yīng)的鍵值后,掃描數(shù)據(jù)頁,如果有包含索引,直接在索引頁就可以提取到需要的數(shù)據(jù)。
上面說了小數(shù)據(jù)量的時(shí)候聚集索引體現(xiàn)不出效果,下面我們繼續(xù)填充數(shù)據(jù)測試 。
填充測試數(shù)據(jù)到1000
表掃描
消息:
表'employee'。掃描計(jì)數(shù)1,邏輯讀取36 次,物理讀取0 次,預(yù)讀0 次,lob 邏輯讀取0 次,lob 物理讀取0 次,lob 預(yù)讀0 次。
聚集索引掃描
消息:
表'employee'。掃描計(jì)數(shù)1,邏輯讀取2 次,物理讀取0 次,預(yù)讀0 次,lob 邏輯讀取0 次,lob 物理讀取0 次,lob 預(yù)讀0 次。
這個(gè)時(shí)候聚集索引的優(yōu)勢就先顯示出來了 O(∩_∩)O
下面在來講講transaction sql 語句 ,大家在網(wǎng)上看到的一些人說 In like left 不使用索引 ,我們動手來測試下看他們說的對不對 ?
刪除employee表的索引
DROP INDEX employee.Idx_emp_username
表 'employee'。掃描計(jì)數(shù) 1,邏輯讀取 371 次,物理讀取 0 次,預(yù)讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預(yù)讀 0 次。
打開IO信息
SET STATISTICS IO ON
SELECT * FROM employee WHERE employee.emp_username in ('劉10000')
消息:
--添加Idx_emp_username聚集索引
CREATE CLUSTERED INDEX Idx_emp_username ON employee (emp_username);
SELECT * FROM employee WHERE employee.emp_username in ('劉10000');
消息:
表 'employee'。掃描計(jì)數(shù) 1,邏輯讀取 3 次,物理讀取 0 次,預(yù)讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預(yù)讀 0 次。
使用索引后邏輯讀取3次,沒有使用索引是371次,IN 很好的使用了索引!
下面我們來測試下 LIKE 是否很好的使用索引
刪除索引
DROP INDEX employee.Idx_emp_username
打開IO 信息
SET STATISTICS IO ON
執(zhí)行查詢
SELECT * FROM employee WHERE employee.emp_username like ('劉1000%')
消息:
表 'employee'。掃描計(jì)數(shù) 1,邏輯讀取 371 次,物理讀取 0 次,預(yù)讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預(yù)讀 0 次。
添加索引
CREATE CLUSTERED INDEX Idx_emp_username ON employee (emp_username);
SET STATISTICS IO ON
SELECT * FROM employee WHERE employee.emp_username like ( '劉1000%');
表 'employee'。掃描計(jì)數(shù) 1,邏輯讀取 3 次,物理讀取 0 次,預(yù)讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預(yù)讀 0 次。
網(wǎng)上很多優(yōu)化的文章寫到查詢不要使用 in like left ,其實(shí)自己動手測試下看看查詢計(jì)劃就一幕了然了 。