SQLSERVER中KeyHashValue的做用(上)

SQLSERVER中KeyHashValue的做用(上)

SQLSERVER中KeyHashValue的做用(下)html

原文的標題是:SQLSERVER在索引下如何找到哈希值的隨想算法

如今知道KeyHashValue的做用了,因此就改了標題~sql

 

測試環境:SQLSERVER2005 開發者版數據庫

真的很差意思,我作實驗的時候到最後仍是沒有找到這個問題的答案ide

問題是這樣的:sqlserver

當經過彙集索引查找和非彙集索引查找的時候,經過哈希碼來匹配,而後找到相應記錄的性能

既然經過哈希碼來匹配,那麼就須要一個hash bucket把全部索引頁面的全部key/value所有加載到hash bucket測試

既然要所有加載到hash bucket就須要讀取全部的索引頁spa

個人測試腳本,我使用SET STATISTICS IO ON來測試是否有讀取索引頁的狀況,可是到最後仍是找不到規律設計

  1 --sql在彙集索引下如何找到哈希值的隨想
  2 
  3 USE master
  4 GO
  5 --新建數據庫IAMDB
  6 CREATE DATABASE SCANDB
  7 GO
  8 
  9 USE SCANDB
 10 GO
 11 
 12 
 13 
 14 --DROP TABLE clusteredtable
 15 --DROP TABLE nonclusteredtable
 16 
 17 
 18 --創建測試表
 19 CREATE TABLE clusteredtable(c1 INT IDENTITY(1,1), c2 VARCHAR (900))
 20 GO
 21 CREATE TABLE nonclusteredtable(c1 INT IDENTITY(1,1), c2 VARCHAR (900))
 22 GO
 23 
 24 
 25 --創建索引
 26 CREATE CLUSTERED INDEX cix_clusteredtable ON clusteredtable([C2])
 27 GO
 28 CREATE  INDEX ix_nonclusteredtable ON nonclusteredtable([C2])
 29 GO
 30 
 31 
 32 --插入測試數據
 33 DECLARE @a INT;
 34 SELECT @a = 1;
 35 WHILE (@a <= 100)
 36 BEGIN
 37     INSERT INTO clusteredtable VALUES ( CAST(@a AS NVARCHAR(2))+replicate('a', 880))
 38     SELECT @a = @a + 1
 39 END
 40 
 41 
 42 DECLARE @a INT;
 43 SELECT @a = 1;
 44 WHILE (@a <= 100)
 45 BEGIN
 46     INSERT INTO nonclusteredtable VALUES ( CAST(@a AS NVARCHAR(2))+replicate('a', 880))
 47     SELECT @a = @a + 1
 48 END
 49 
 50 
 51 
 52 
 53 --查詢數據
 54 SELECT * FROM clusteredtable  ORDER BY [c1] ASC
 55 SELECT * FROM nonclusteredtable  ORDER BY [c1] ASC
 56 
 57 
 58 CREATE TABLE DBCCResult (
 59 PageFID NVARCHAR(200),
 60 PagePID NVARCHAR(200),
 61 IAMFID NVARCHAR(200),
 62 IAMPID NVARCHAR(200),
 63 ObjectID NVARCHAR(200),
 64 IndexID NVARCHAR(200),
 65 PartitionNumber NVARCHAR(200),
 66 PartitionID NVARCHAR(200),
 67 iam_chain_type NVARCHAR(200),
 68 PageType NVARCHAR(200),
 69 IndexLevel NVARCHAR(200),
 70 NextPageFID NVARCHAR(200),
 71 NextPagePID NVARCHAR(200),
 72 PrevPageFID NVARCHAR(200),
 73 PrevPagePID NVARCHAR(200)
 74 )
 75 
 76 TRUNCATE TABLE [dbo].[DBCCResult]
 77 
 78 INSERT INTO DBCCResult EXEC ('DBCC IND(SCANDB,nonclusteredtable,-1) ')
 79 
 80 SELECT * FROM [dbo].[DBCCResult] ORDER BY [PageType] DESC 
 81 
 82 DBCC TRACEON(3604,-1)
 83 GO
 84 DBCC PAGE(SCANDB,1,89,3) 
 85 GO
 86 
 87 checkpoint 
 88 DBCC DROPCLEANBUFFERS
 89 DBCC freesystemcache('all')
 90 GO
 91 -----------------------------------
 92 SET STATISTICS IO ON
 93 GO
 94 --彙集索引查找
 95 SELECT * FROM clusteredtable WHERE [c2]='18aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
 96 SET STATISTICS IO OFF
 97 GO
 98 
 99 
100 
101 (1 行受影響)
102'clusteredtable'。掃描計數 1,邏輯讀取 4 次,物理讀取 2 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。
103 
104 
105 
106 
107 ----------------------------------------------------------------------------------------
108 checkpoint 
109 DBCC DROPCLEANBUFFERS
110 DBCC freesystemcache('all')
111 GO
112 -----------------------------------
113 SET STATISTICS IO ON
114 GO
115 --索引查找  、RID查找 、嵌套循環
116 SELECT * FROM nonclusteredtable WHERE [c2]='17aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
117 SET STATISTICS IO OFF
118 GO
119 
120 
121 
122 (1 行受影響)
123'nonclusteredtable'。掃描計數 1,邏輯讀取 5 次,物理讀取 1 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。
View Code

彙集索引表的狀況

非彙集索引表的狀況

 

今天中午跟高文佳兄討論了很長時間,我把關鍵討論部分貼出來,你們參考參考,討論的最後結果是:尚未解釋到keyhashvalue字段實際的做用

感謝高文佳,頭腦很是靈活

ō笑東風ō 9:27:10 
對了 你那個hash的問題 
ō笑東風ō 9:27:21 
感受你研究的方向不對
ō笑東風ō 9:28:05 
當經過彙集索引查找和非彙集索引查找的時候,經過哈希碼來匹配,而後找到相應記錄的
樺少 9:28:53 
請指教
ō笑東風ō 9:29:00 
查找時不會使用hash來查找 由於hash值沒有排序 沒法最快查找
樺少 9:29:18 
ō笑東風ō 9:29:20  應該是按照key來查找
 
樺少 9:33:52
ō笑東風ō  9:29:20
應該是按照key來查找
樺少 9:33:55
說說你的思路
ō笑東風ō 9:34:18
在索引裏已經按照KEY排序 對吧
ō笑東風ō 9:34:34
而按照key排序 能最快找到想要的值
樺少 9:35:38
key排序有爭議
樺少 9:35:42
又怎樣
樺少 9:35:58
你尚未說清楚

ō笑東風ō 9:37:21
先說key查找的

我記得你有篇blog裏說過hashjoin
樺少 9:39:38
哪三個經典鏈接沒有寫
ō笑東風ō 9:40:56
反正個人觀點是key查找最快 無須再使用hash來定位
ō笑東風ō 9:41:26
而只有在hash join纔會用到hash

笑東風ō  9:40:56
反正個人觀點是key查找最快 無須再使用hash來定位
而只有在hash join纔會用到hash

樺少 12:50:35
你想好啦嗎
ō笑東風ō 12:51:57
嗯 我仍是認爲聚簇索引和非聚簇索引只存在key lookup
樺少 12:55:46
key lookup
的原理是什麼
樺少 12:55:52
操做步驟是怎樣的
樺少 12:55:56
你知道嗎
ō笑東風ō 12:59:31
就是平衡樹的原理
樺少 13:00:31

ō笑東風ō 13:00:38
使用平衡樹 對上百萬的INT值進行查找只須要4步
樺少 13:00:58
你查找的時候是否須要從磁盤讀取索引頁面到內存
ō笑東風ō 13:01:05

樺少 13:01:06
先不說他用多少步
樺少 13:01:08
性能有多好
樺少 13:01:26
從磁盤讀取整個表的索引頁面到內存
樺少 13:01:29
整個表
樺少 13:01:41
而後構成你說的所謂的平衡樹

樺少 13:01:46 
對吧
ō笑東風ō 13:02:06 
樺少 13:02:52 
個人問題就是這個
樺少 13:03:01 
我用statictis io
樺少 13:03:10 
看不出他會讀取全部的索引頁面
ō笑東風ō 13:04:25 
一次seek 固然不會讀取全部的頁面
ō笑東風ō 13:04:48 
只有scan纔會讀取全部頁面
樺少 13:05:36 
你仍是不明白我問的問題
樺少 13:06:18 
我說的是索引頁
樺少 13:06:26 
不是數據頁
ō笑東風ō 13:06:45 
索引也同樣 
ō笑東風ō 13:06:50 
等等我給你作個demo
樺少 13:08:00 
還有 ō笑東風ō 13:08:30 
我如今有[BackupTestDB].[dbo].[TB1] 表中數據有245461條
樺少 13:08:43 
你說用二叉樹
ō笑東風ō 13:08:44 
樺少 13:08:47 
若是是這樣
樺少 13:08:59 
那麼,keyhashvalue就沒有意義了
ō笑東風ō 13:09:06 
不是二叉樹 是B樹
樺少 13:09:15 
樺少 13:09:23 
b樹 樺少 13:09:51 
因此我從hash bucket的角度去思考
ō笑東風ō 13:10:22 
hash桶這個概念是爲了HASH JOIN才產生的
樺少 13:10:36 
若是用b樹,從第一個最左邊的葉子節點開始從磁盤讀取索引頁面,組裝一棵B樹
ō笑東風ō 13:11:05 
繼續
樺少 13:11:23 
若是是這樣,keyhashvalue這個字段根本不須要
樺少 13:12:12 
用到key alue的均可以用桶這個概念啊
樺少 13:12:19 
我以爲
樺少 13:12:47 
我以爲不用死磕書本
樺少 13:13:06 
死磕書本等於讀死書
ō笑東風ō 13:14:28 
樺少 13:14:49 
樺少 13:15:58 
我之前作實驗的時候也看到過keyhashvalue所有爲null
樺少 13:16:47 
想寫在SQLSERVER彙集索引與非彙集索引的再次研究(上)文章的最後面的
樺少 13:16:58 
可是由於解釋不了這個現象
樺少 13:17:01 
最後沒有寫
樺少 13:19:42 
爲什麼我提出這個想法
樺少 13:19:52 
其實我也是從性能和速度考慮的
ō笑東風ō 13:20:09 
騷等
樺少 13:20:21 
個人想法是:sqlserver有可能不用你剛纔說的B樹來找記錄
ō笑東風ō 13:20:31 
我懷疑這個HASHvalus是爲了在seek時作比較用的
樺少 13:20:45 
我畫圖給你看
樺少 13:22:42 
當我用匯集索引查找的時候
樺少 13:23:11 
key的字段是id
樺少 13:23:25 
表中的字段是id
樺少 13:23:32 
id是彙集索引字段
樺少 13:23:50 
value是數據頁面號
樺少 13:24:12 
我要找id爲9的那條記錄
樺少 13:24:58 
等一下
樺少 13:25:02 
圖還沒畫好
樺少 13:26:27 
樺少 13:26:51 
我須要將索引頁69,88,102讀取到內存
樺少 13:26:57 
構成一棵b樹
樺少 13:27:13 
從左到右,從上到下查找
樺少 13:27:30 
直至找到key爲9那條記錄
樺少 13:27:59 
若是我select的是id爲3的那條記錄
樺少 13:28:17 
我就不用讀取索引頁88,102讀取到內存
樺少 13:28:23 
只須要讀取索引頁面69
 
樺少 13:30:29 
改一下,數據頁面編號沒有英文字母的
樺少 13:30:30 
樺少 13:30:37 
睡醒再聊
樺少 14:05:59 
當我找id爲9的記錄的時候
樺少 14:06:16 
我須要掃描索引頁面69和索引頁面88
ō笑東風ō 14:06:28 
不須要掃面69
ō笑東風ō 14:06:42 
只須要掃描88和102
樺少 14:06:43 
說錯了
樺少 14:06:54 
是的
樺少 14:07:15 
可是你也須要從磁盤讀取索引頁面69吧
樺少 14:07:22 
組裝出一棵b樹
樺少 14:08:56 
逐行逐行掃描 索引頁面88和102裏的記錄
樺少 14:09:08 
直到掃描到id爲9的那條記錄才中止
樺少 14:09:14 
個人想法是
樺少 14:09:51 
個人想法是:sqlserver有可能不用你剛纔說的B樹來找記錄
ō笑東風ō 14:09:53 
頁面內掃描是這樣
樺少 14:10:59 
將全部索引頁面的key列和value列放進去hash桶
樺少 14:11:07 
ō笑東風ō 14:11:31 
我剛在我本地跑了下你的腳本 SQL SERVER 2008 SP2
樺少 14:11:32 
經過算法查找到id爲9的那一條記錄
ō笑東風ō 14:11:38 
沒有hashkey
ō笑東風ō 14:11:59 
你的平臺是什麼
樺少 14:12:04 
這樣就不用掃描:索引頁面88和102裏的記錄
樺少 14:12:32 
這個過程中,也是須要讀取頁面69,88,102
樺少 14:12:39  可是他就不用掃描
樺少 14:12:47  sql2005
ō笑東風ō 14:13:14 
我到時有一種猜想
樺少 14:13:57 
否則無辦法解釋keyhashvalue這個字段
ō笑東風ō 14:14:07 
當好比較大字符串的時候 若是將字符串先hash後比較hash值 若是hash值相同 在比較字符串 這樣效率會高一些
樺少 14:16:54 
這種方法有一個缺點
ō笑東風ō 14:17:17 
什麼缺點
樺少 14:18:10 
若是我select的是id爲3的那條記錄 他都會把全部索引頁面讀取到內存
樺少 14:18:20 
而不像B樹
樺少 14:18:36 
樺少 14:18:43 
由於他須要在桶裏面找
ō笑東風ō 14:19:53 
若是按照你所想的這樣 沒法快讀定位某一個值的行 
ō笑東風ō 14:20:03 
必須掃描全部頁
ō笑東風ō 14:20:17 
除非對hashvalue進行排序
樺少 14:21:01 
掃描全部索引頁面
樺少 14:21:20 
把全部索引頁面裏的keyhashvalue讀取到桶裏面
樺少 14:21:22 
而後查找
ō笑東風ō 14:26:27 
並且到hash桶後 還須要排序 若是不排序 須要所有遍歷
樺少 14:27:33 
嗯嗯
樺少 14:27:43 
因此個人文章標題是:隨想
ō笑東風ō 14:29:36 
我知道有一種程序設計 是這樣作的 就是對大字段作hash 而後對hash做爲一列存儲 對hash列創建索引 
ō笑東風ō 14:30:04 
這樣作等值查詢時能提升查詢效率
樺少 14:32:58 
高兄你是否是想偏了
樺少 14:33:09 
不是隻有大字段纔有hash
ō笑東風ō 14:33:38 
我只是說這是一種設計思路 
樺少 14:33:39 
ō笑東風ō 14:34:14 
任何數據均可以被hash
樺少 14:34:37 
不過這裏好像說不過去
ō笑東風ō 14:36:10 
並且林兄你看到的這些都是非葉子節點哈
樺少 14:50:22 
固然是非葉子節點啦
樺少 14:50:33 
葉子節點就是數據頁面
ō笑東風ō 14:51:28 
這個hashvalue應該跟seek無關
樺少 14:52:39 
因此我才說無辦法解釋嘛
ō笑東風ō 14:59:25 
嗯嗯 
相關文章
相關標籤/搜索