通過以下語句清楚資料緩存并開啟IO統計:
DBCC DROPCLEANBUFFERS; --清除緩存
SET STATISTICS IO ON; --開啟IO統計
SELECT * FROM FoodCorp;
示例:
一、相關定義
SQL SERVER 資料庫引擎當遇到一個查詢語句時,SQL SERVER資料庫引擎會分别生成執行計劃(占用CPU和記憶體資源),同時存儲引擎讀取 IAM 以生成必須要讀取的磁盤位址排序清單。這使 SQL Server 得以将其 I/O 優化為大型有序讀取,根據它們在磁盤上的位置按順序完成。磁盤中取得需要取的資料(占用I/O資源,這就是預讀),注意,兩個步驟是并行的,SQL SERVER通過這種方式可以讓計算和 I/O 重疊進行,進而充分利用 CPU 和磁盤,進而提高性能。
掃描計數:查詢資料時對涉及到的表被通路次數或涉及到的索引的掃描次數。對于查詢中不包括連接配接指令時,這一資訊并不是十分有用,但如果查詢中包含有一個或多個連接配接,則十分有用。
一個循環外部的表的掃描計數值為1,但對于一個循環内的表而言,其值為循環的次數。可以想象得到,對于一個循環内的表而言,其掃描計數值越小,它所使用的資源越少,查詢的性能也就越高。是以在調節一個帶連接配接的查詢的性能時,需要關注掃描計數的值,在進行調節時,注意觀察它是增加還是減少了。
邏輯讀: 這是SET STATISTICS IO或SET STATISTICS TIME指令提供的最有用的資料。SQL Server在對任何資料進行操作前,必須首先從磁盤中讀取資料所在的資料頁或索引頁,并把資料頁或索引頁存到資料緩沖區高速緩存中。
邏輯讀是指SQL Server為得到查詢中的結果而必須從資料緩沖區高速緩存讀取的頁數。在執行查詢時,SQL Server不會讀取比實際需求多或少的資料, 是以,當在相同的資料集上執行同一個查詢,得到的邏輯讀的數字總是相同的。
在每次執行同一查詢時,這個數值是不會變化的。是以,在進行查詢性能的調節時,這是一個可以用來衡量你的調節措施是否成功的一個很好的标準。
在對查詢的性能進行調節時,如果邏輯讀值下降,就表明查詢使用的伺服器資源減少,查詢的性能有所提高。如果邏輯讀值增加,則表示調節措施降低了查詢的性能。在其他條件不變的情況下,一個查詢使用的邏輯讀越少,其效率就越高,查詢的速度就越快。
實體讀:指的是,在執行真正的查詢操作前,SQL Server必須從磁盤上向資料緩沖區高速緩存中讀取它所需要的資料。在SQL Server開始執行查詢前,它要作的第一件事就是檢查它所需要的資料是否在資料緩沖區高速緩存中,如果在,就從中讀取,如果不在,SQL Server必須首先将它需要的資料從磁盤上讀到資料緩沖區高速緩存中。
SQL Server在執行實體讀時比執行邏輯讀需要更多的伺服器資源。是以,在理想情況下,我們應當盡量避免實體讀操作。
在對查詢的性能進行調節時,可以忽略實體讀而隻專注于邏輯讀。SQL Server在執行查詢時所需要的實體讀次數不可能通過性能調節而減少的。減少實體讀的次數是DBA的一項重要工作,但它涉及到整個伺服器性能的調節,而不僅僅是查詢性能的調節。在進行查詢性能調節時,我們不能控制資料緩沖區高速緩存的大小或伺服器的忙碌程度以及完成查詢所需要的資料是在資料緩沖區中還是在磁盤上,唯一我們能夠控制的資料是得到查詢結果所需要執行的邏輯讀的次數。
減少實體讀次數、加快SQL Server運作速度的一種方式是確定伺服器的實體記憶體足夠多。
預讀:預讀表示SQL Server在執行預讀機制時從磁盤上讀取的資料頁或索引頁。為了優化其性能,SQL Server資料引擎首先預測執行查詢執行計劃所需的資料和索引頁,然後在查詢實際使用這些頁之前将它們讀入緩沖區高速緩存。根據SQL Server對資料需求預測的準确程度,預讀的資料頁可能有用,也可能沒用。與實體讀一樣,這個值在查詢性能調節中也沒有什麼用處。
注意:一個緩沖區就是一個 8KB 大小的記憶體頁
二、分析
SQL SERVER資料存儲的方式:存儲的最小機關為頁(Page).每一頁大小為8k,SQL SERVER對于頁的讀取是原子性,要麼讀完一頁,要麼完全不讀,不會有中間狀态。而頁之間的資料組織結構為B樹。是以SQL SERVER對于邏輯讀,預讀,和實體讀的機關是頁。
SQL SERVER一頁的總大小為:8K
頁存儲的資料為:8192位元組-96位元組(頁頭)-36位元組(行偏移)=8060位元組
是以每一頁用于存儲的實際大小為8060位元組。
通過表屬性→存儲,看到這個表的資料空間為5.336M:
可以通過公式大概推算出占用了多少頁:
5.336*1024*1024/8060(每頁的資料容量)≈ 694 - 表中非資料占用的空間 ≈687(邏輯讀取數)
SQL SERVER查詢執行的步驟如果從微觀來看,那将會非常多。這裡為了講述邏輯讀等概念,從比較高的抽象層次來看:
當遇到一個查詢語句時,SQL SERVER會走第一步,分别為生成執行計劃(占用CPU和記憶體資源),同步的用估計的資料去磁盤中取得需要取的資料(占用IO資源,這就是預讀),注意,兩個第一步是并行的,SQL SERVER通過這種方式來提高查詢性能。
然後查詢計劃生成好了以後去緩存讀取資料.當發現緩存缺少所需要的資料後讓緩存再次去讀硬碟(實體讀)。
最後從緩存中取出所有資料(邏輯讀)。
示例中的“ 預讀703次 ”即為估計的頁數,可以通過這個DMV看到該資料:
SELECTpage_countFROM sys.dm_db_index_physical_stats(DB_ID('foodtrace_fwq'),OBJECT_ID('FoodCorp'),NULL,NULL,'sampled')
當我們第一次查詢完成後,再次進行查詢時,所有請求的資料這時已經在緩存中,SQL SERVER這時隻要對緩存進行讀取就行了,也就是隻用進行邏輯讀。