適用於:SQL Server
Azure SQL 受控執行個體
SQL Server 資料庫引擎執行個體中的 I/O 包括邏輯和實體讀取。 每次 Database Engine 從 緩衝區快取要求頁面,也稱為 緩衝池時,就會發生邏輯讀取。 如果頁面目前不在緩衝區快取中,實體讀取會先將頁面從磁碟複製到快取。
資料庫引擎實例所產生的讀取要求是由關係型引擎所控制,並由儲存引擎優化。 關係型引擎會決定最有效的存取方法(例如數據表掃描、索引掃描或索引鍵讀取)。 儲存引擎的存取方法和緩衝區管理元件會決定要進行的一般讀取模式,並優化實作存取方法所需的讀取。 負責執行批次作業的執行緒會安排讀取作業。
預先閱讀
資料庫引擎支援稱為「預先讀取」的效能最佳化機制。 預先讀取會提前估算查詢執行計劃所需的數據和索引頁面,並將這些頁面在查詢使用前載入緩衝區快取。 此程式可讓計算和 I/O 重疊,充分利用 CPU 和磁碟。
預先讀取機制可讓 Database Engine 從一個檔案讀取最多 64 個連續頁面(512 KB)。 讀取將作為單一分散-聚集讀取,執行到緩衝快取中適當數量的(可能不連續的)緩衝區。 如果範圍中的任何頁面已經存在於緩衝區快取中,讀取完成時會捨棄讀取中的對應頁面。 如果快取中已經有對應的頁面,則頁面範圍可能會從任一端進行「修剪」。
預先讀取有兩種:一種用於 數據頁 ,另一種用於 索引頁。
讀取數據頁
Database Engine 用來讀取數據頁的數據表掃描很有效率。 SQL Server 資料庫中的索引配置對應 (IAM) 頁面會列出資料表或索引所使用的範圍。 儲存引擎可以讀取 IAM,以建立必須讀取之磁碟位址的排序清單。 如此可讓儲存引擎根據磁碟上的讀取位置,將其 I/O 操作最佳化為依序執行的大型循序讀取。 如需 IAM 頁面的詳細資訊,請參閱 管理物件所使用的空間。
讀取索引頁
儲存引擎會依照索引鍵順序循序讀取索引頁。 例如,下圖所示為一組簡化的分葉頁,分頁上含有一組索引鍵值,以及對應分葉頁的中繼索引節點。 如需索引中頁面結構的詳細資訊,請參閱 叢集和非叢集索引。
儲存引擎利用位於葉節點層級之上的中繼索引頁中的資訊,規劃包含索引鍵的頁面的序列式預讀。 如果要求獲取從ABC到DEF的所有鍵,儲存引擎會先讀取位於葉頁上方的索引頁。 不過,它不只是依序從第 504 頁讀取每個數據頁到第 556 頁(具有指定範圍索引鍵的最後一頁)。 否則,儲存引擎會掃描中繼索引頁,然後建立必須讀取之分葉頁的清單。 儲存引擎接著依照索引鍵的順序排程所有的讀取。 同時儲存引擎也識別出 504/505 和 527/528 頁是連續的,並執行單一的散佈讀取,從而在單一作業中讀取相鄰頁面。 當序列作業中有許多要擷取的分頁時,儲存引擎會一次排程一個讀取區塊。 當這些讀取的子集完成時,儲存引擎會安排相同數量的新讀取,直到排定所有必要的讀取為止。
儲存引擎會使用 預先擷取 來加速非叢集索引的基表查閱速度。 非叢集索引的葉資料列內含指標,這些指標指向各特定鍵值的資料列。 當儲存引擎透過非叢集索引的分葉頁面讀取時,它也會開始為已擷取指標的數據列排程異步讀取。 這可讓儲存引擎先從基礎表擷取數據列,再完成非叢集索引的掃描。 不論資料表有沒有叢集索引,都會使用預先提取。 SQL Server Enterprise 版本使用比其他 SQL Server 版本更多的預先擷取,讓更多頁面可以事先閱讀。 任何版本中都無法設定預先擷取的層級。 如需非叢集索引的詳細資訊,請參閱 叢集和非叢集索引。
進階掃描
在 SQL Server Enterprise 版本中,進階掃描功能可讓多個工作共用完整數據表掃描。 如果 Transact-SQL 陳述式的執行計畫需要掃描資料表中的資料頁,而資料庫引擎偵測到該資料表已經由另一項執行計畫進行掃描,資料庫引擎會在第二個掃描的目前位置上將第二個掃描聯結至第一個掃描。 資料庫引擎一次會讀取一頁,並將每個分頁的資料列同時傳送給這兩項執行計畫。 這樣一直繼續到表格結束為止。
此時,第一個執行計劃具有掃描的完整結果。 不過,第二個執行計劃仍必須擷取已讀取的數據頁,再聯結進行中的掃描。 所以第二個執行計畫的掃描會繞回資料表的第一個資料頁,然後往前掃描,直到與第一個掃描聯結那一點。 任何數量的掃描都可以如上述結合。 Database Engine 會持續迴圈處理數據頁,直到完成所有掃描為止。 這個機制也稱為「旋轉木馬掃描」,並示範為什麼不使用ORDER BY子句,就無法保證從SELECT語句傳回的結果順序。
例如,假設有一個 500,000 個分頁的資料表。
UserA 會執行需要掃描數據表的 Transact-SQL 語句。 當掃描已處理 100,000 頁時, UserB 會執行另一個掃描相同數據表的 Transact-SQL 語句。 資料庫引擎會排定一組讀取要求,讀取 100,001 以後的分頁,並將每個分頁的資料列同時傳回給兩個掃描。 當掃描到達第 200,000 頁時, UserC 執行另一個掃描相同數據表的 Transact-SQL 語句。 從第 200,001 個分頁起,資料庫引擎會將每個讀取的分頁中的資料列傳回給三個掃描。 讀取第 500,000 行資料列之後,掃描 UserA 即告完成,而掃描 UserB 和 UserC 則重新開始,從第 1 頁開始讀取頁面。 當 Database Engine 到達第 100,000 頁時,就會完成掃描 UserB 。
UserC掃描之後會持續單獨執行,直到讀取第 200,000 頁為止。 這個時候,就完成了所有的掃描。
如果沒有進階掃描,每個使用者都必須搶奪緩衝記憶體空間,從而導致磁碟讀寫頭爭用的情況。 所以每個使用者都會各讀取同一頁面一次,而不是只讀取一次,再由多個使用者共用,如此會降低效能並消耗資源。
相關內容
- #B0 頁面和範圍架構指南 #C1
- 在 Database Engine 中寫入頁面