在眾多數(shù)據(jù)庫(kù)當(dāng)中,SQL Server是我們比較常見的數(shù)據(jù)庫(kù)。因此對(duì)于許多新手來說,對(duì)于SQL Server數(shù)據(jù)庫(kù)查詢優(yōu)化器如何工作并不清楚。SQL Server 數(shù)據(jù)庫(kù)引擎的核心是兩個(gè)主要組件:存儲(chǔ)引擎和查詢處理器(也稱為關(guān)系引擎)。存儲(chǔ)引擎:以優(yōu)化并發(fā)性并同時(shí)保持?jǐn)?shù)據(jù)完整性的方式照顧磁盤和內(nèi)存之間的數(shù)據(jù)讀取。查詢處理器:1.負(fù)責(zé)通過Query Optimizer設(shè)計(jì)查詢計(jì)劃;2.由Execution Engine根據(jù)該計(jì)劃執(zhí)行查詢。
查詢處理器執(zhí)行以下操作:
1.查詢解析
2.將查詢綁定到對(duì)象
3.生成可能的執(zhí)行計(jì)劃
4.每個(gè)計(jì)劃的成本評(píng)估
執(zhí)行引擎執(zhí)行以下操作:
1.查詢執(zhí)行
2.計(jì)劃緩存
解析將SQL查詢轉(zhuǎn)換為初始樹表示形式。綁定主要涉及名稱解析。
搜索空間
我們將給定查詢的搜索空間定義為該查詢的所有可能執(zhí)行計(jì)劃的集合,并且該搜索空間中的任何可能計(jì)劃都返回相同的結(jié)果。
生成候選人執(zhí)行計(jì)劃
如前所述,查詢優(yōu)化器的基本目的是為您的查詢找到有效的執(zhí)行計(jì)劃。即使對(duì)于相對(duì)簡(jiǎn)單的查詢,也可能有很多不同的方法來訪問數(shù)據(jù)以產(chǎn)生相同的最終結(jié)果。因此,查詢優(yōu)化器必須從可能的大量候選執(zhí)行計(jì)劃中選擇最佳的計(jì)劃,并且做出明智的選擇非常重要,因?yàn)閷⒔Y(jié)果返回給用戶的時(shí)間可能會(huì)有所不同瘋狂,取決于選擇哪個(gè)計(jì)劃。
查詢優(yōu)化器必須在優(yōu)化時(shí)間和計(jì)劃質(zhì)量之間取得平衡。SQL Server不會(huì)進(jìn)行詳盡的搜索,而是嘗試盡快找到合適的有效計(jì)劃。
評(píng)估每個(gè)計(jì)劃的成本
查詢優(yōu)化器需要估算這些計(jì)劃的成本,然后選擇成本最低的計(jì)劃。為了估算計(jì)劃的成本,它使用考慮了I / O,CPU和內(nèi)存等資源使用的成本核算公式來估算該計(jì)劃中每個(gè)物理操作員的成本。
基數(shù)估計(jì):查詢計(jì)劃的成本估計(jì)主要取決于物理操作員使用的算法以及估計(jì)需要處理的記錄數(shù);記錄數(shù)量的這種估計(jì)稱為基數(shù)估計(jì)。
查詢執(zhí)行和計(jì)劃緩存
優(yōu)化查詢后,執(zhí)行引擎將使用生成的計(jì)劃來檢索所需的數(shù)據(jù)。生成的執(zhí)行計(jì)劃可以存儲(chǔ)在內(nèi)存中,在計(jì)劃緩存中,以便在再次執(zhí)行同一查詢時(shí)可以重新使用它。
但是,對(duì)于給定查詢,重用現(xiàn)有計(jì)劃可能并不總是最佳解決方案。根據(jù)表中數(shù)據(jù)的分布,給定查詢的最佳執(zhí)行計(jì)劃可能會(huì)根據(jù)所述查詢中提供的參數(shù)而有很大差異,并且稱為參數(shù)嗅探的行為可能會(huì)導(dǎo)致選擇次優(yōu)計(jì)劃。
即使執(zhí)行計(jì)劃在計(jì)劃緩存中可用,某些元數(shù)據(jù)更改或?qū)?shù)據(jù)庫(kù)內(nèi)容所做的足夠大的更改也可能使現(xiàn)有計(jì)劃無效或次優(yōu),從而導(dǎo)致現(xiàn)有計(jì)劃無效從計(jì)劃緩存中丟棄并生成新的優(yōu)化。
重新編譯
您可以強(qiáng)制SQL Server每次運(yùn)行時(shí)重新編譯存儲(chǔ)過程。這樣做的好處是,每次運(yùn)行時(shí)都會(huì)創(chuàng)建最佳查詢計(jì)劃。但是,重新編譯是占用大量CPU的操作。對(duì)于經(jīng)常運(yùn)行的存儲(chǔ)過程或在已經(jīng)受到CPU資源限制的服務(wù)器上,這可能不是理想的解決方案。要記住的另一件事是,這些計(jì)劃不會(huì)存儲(chǔ)在緩存中,這使它們更難找到是否有問題。
ALTER PROCEDURE Get_OrderID_OrderQty
@ProductID INT
WITH RECOMPILE
AS
SELECT SalesOrderDetailID, OrderQty
FROM Sales.SalesOrderDetail
WHERE ProductID = @ProductID;
提示
另一個(gè)選擇是使用OPTIMIZE FOR查詢提示。這告訴SQL Server在編譯計(jì)劃時(shí)使用指定的值。如果通過測(cè)試可以找到每次生成“足夠好的”計(jì)劃的值,并且鼠標(biāo)和大象的性能都可以接受,那么這對(duì)您來說是一個(gè)不錯(cuò)的選擇。
但是,請(qǐng)了解您正在引導(dǎo)查詢優(yōu)化器。您說的是您的最佳想法。OPTIMIZE FOR的最大缺點(diǎn)在于數(shù)據(jù)分布發(fā)生變化的表。更改速度越快,此提示可能會(huì)過時(shí)。如果您提供的價(jià)值在一個(gè)月或一年中不是最優(yōu)的,該怎么辦?您需要有一種定期檢查和修訂此方法的方法。
ALTER PROCEDURE Get_OrderID_OrderQty
@ProductID INT
AS
SELECT SalesOrderDetailID, OrderQty
FROM Sales.SalesOrderDetail
WHERE ProductID = @ProductID
OPTION (OPTIMIZE FOR (@ProductID=945));
現(xiàn)實(shí)情況是,即使經(jīng)過30多年的研究,查詢優(yōu)化器還是非常復(fù)雜的軟件,仍然面臨一些技術(shù)挑戰(zhàn)。結(jié)果,即使在為Query Optimizer提供了所需的所有信息之后,甚至在似乎沒有任何明顯問題的情況下,您仍然可能無法獲得有效的計(jì)劃。
通過上述介紹,SQL Server查詢優(yōu)化器如何工作相信大家已經(jīng)清楚了吧,想了解更多關(guān)于SQL Server數(shù)據(jù)庫(kù)信息,請(qǐng)繼續(xù)關(guān)注中培偉業(yè)。