在SQLSERVER查詢分析器中,當我們用Set Statistics on 語句來統計SQL語句或者存儲過程I/O的時候,
SQLSERVER會顯示幾個概念去詞語:邏輯讀取,物理讀取,預讀。
如下:
(1 行受影響)
表 't2'。掃描計數 1,邏輯讀取 3282 次,物理讀取 44 次,預讀 3282 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。
那么,這幾個詞語代表什么意思呢?我們怎么根據這些來了解SQL語句或者存儲過程的I/O過程呢?
預讀:用於估計信息,去硬盤讀取數據到緩存。
物理讀:查詢計划生成以后,如果發現緩存缺少所需要的數據,讓緩存再次去讀硬盤數據。如果內存里沒有緩存數據或者執行計划(如果SQL語句發生了改變,
那么執行計划將不能重用,需要重新生成新的執行計划),那么SQLSERVER就要去硬盤讀取這些數據,這個時候就是物理讀取,我們大家都知道,硬盤速度
與內存速度根本不在一個數量級上,所以物理讀是比較慢的。
邏輯讀:SQLSERVER去內存里的緩存取數據或者執行計划,所以邏輯讀是比較快的。
SQLSERVER存儲的最小單位是頁,每一頁大小為8K,即8*1024=8192字節,SQLSERVER對頁的讀取是原子性的,即要么讀完一頁,要么完全不讀。即使
僅僅要獲得一條數據,也要讀完該頁,而頁之間的數據組織結構為B樹結構。所以SQLSERVER對於邏輯讀,物理讀,預讀的單位是頁。
先來看一個查詢:
DBCC DROPCLEANBUFFERS --清空緩存
SET STATISTICS IO ON --開啟IO統計
SELECT * FROM SAMPLE --查詢
顯示消息如下:
(147517 行受影響)
表'SAMPLE'。掃描計數 1,邏輯讀取2237次,物理讀取6次,預讀2226次,lob讀取0次
上表的大小事17.406M。
每一頁存儲的數據是8K=8192字節-96字節(頁頭)-36字節(行偏移)=8060字節。
17.406*1024*1024/8060約等於2264.
另外表中還有一些非數據占用的空間,因此上式的結果約等於邏輯讀次數。
基本上,邏輯讀,物理讀,預讀都等於是掃描了多少個頁。
SQLSERVER的查詢從理解各種讀的步驟來看,可以理解為下圖
通過上圖來解釋下各種讀的方式:
SQLSERVER執行一個查詢語句的時候,SQLSERVER會執行第一個步驟,即生成查詢計划,同時用估計的數據去磁盤讀取數據(預讀)
,這兩個都是第一步,是並行的。SQLSERVER通過這種方式來提高查詢性能。
當查詢計划生成好以后,開始去緩存讀取數據,當發現緩存缺少所需要的數據的時候,讓緩存再次去硬盤讀取數據(物理讀),然后從緩存
中取出所有數據(邏輯讀)。
估計的頁數可以通過DMV來看到
select pagecount from sys.dm_db_index_physical_stats
(DB_ID('TESTDATACENTER'),OBJECT_ID('SAMPLE'),null,null,'sampled')
顯示結果如下:
SQLSERVER就是根據這個數值進行預讀的。
如果我們此時再執行上面的查詢語句
select * from sample --查詢
看到消息如下:
(147517 行受影響)
表'SAMPLE'。掃描計數1,邏輯讀取2237次,物理讀取0次,預讀0次,lob邏輯讀取0次。
讀者也許不明白了,為什么這次全部都是邏輯讀取呢?
答案是因為剛才執行過這樣一個查詢,執行計划與數據都在緩存當中,所以只需要從緩存中讀取就可以了,
不需要再讀取硬盤。
本文系自己消化並轉載
地址:http://www.studyofnet.com/news/94.html。