Ad hoc 概念解釋

Ad hoc 概念解釋

ad hoc 一般都說是即席查詢,當到底什麼是即席查詢,也沒有說清楚,讓人一頭霧水,在wikipedia上的解釋如下:

 

ad hoc 允許終端用戶自己去建立特定的、自定義的查詢請求。通常是通過一個用戶友好圖形界面來進行數據查詢而無需用戶對 SQL 或者數據庫架構有深入的瞭解。

stackOverflow上的解釋如下:

Ad hocis latin for "for this purpose". You might call it an "on the fly" query, or a "just so" query. It's the kind of SQL query you just loosely type out where you need it

var newSqlQuery = "SELECT * FROM table WHERE id = " + myId;

...which is an entirely different query each time that line of code is executed, depending on the value of myId. The opposite of an ad hoc query is a predefined query such as a Stored Procedure, where you have created a single query for the entire generalized purpose of selecting from that table (say), and pass the ID as a variable.


讓代碼解釋下什麼是Ad hoc,就一目瞭然了。在SSMS中如下的查詢語句即爲Ad Hoc查詢:

 

use AdventureWorks2008R2
go
SELECT  soh .SalesOrderNumber  , 
        sod.ProductID 
FROM    Sales.SalesOrderHeader  AS soh 
         INNER  JOIN Sales.SalesOrderDetail  AS sod 
                ON soh.SalesOrderID = sod.SalesOrderID  
WHERE    soh.SalesOrderNumber  = 'SO43662' 
 
SELECT  soh .SalesOrderNumber  , 
        sod.ProductID 
FROM    Sales.SalesOrderHeader  AS soh 
         INNER  JOIN Sales.SalesOrderDetail  AS sod 
                ON soh.SalesOrderID = sod.SalesOrderID  
WHERE    soh.SalesOrderNumber  = 'SO58928' 
 

這種 hard-code 查詢通常是臨時的,有特殊目的的,與之對應的是參數化的查詢,看如下的TSQL代碼:

declare @orderNumber nvarchar(50)
SELECT  soh .SalesOrderNumber  , 
        sod.ProductID 
FROM    Sales.SalesOrderHeader  AS soh 
         INNER  JOIN Sales.SalesOrderDetail  AS sod 
                ON soh.SalesOrderID = sod.SalesOrderID  
WHERE    soh.SalesOrderNumber  = @orderNumber 

 

這種查詢爲參數化查詢,生成的執行計劃可以重用,而ad hoc 生成的執行計劃不能重用,每次都需要compile一次,消耗相當多的CPU資源,當遇到內存壓力時,這些執行一次的執行計劃

首先被清除掉,爲了避免這種情況產生的代價,在數據庫級別有個選項parameterization,可以讓系統自動把Ad hoc 查詢 轉化成參數化查詢而重用執行計劃。

 

在C#代碼中的Ad hoc 查詢SQL又是如何編寫的呢?

 

cmd.CommandType = CommandType.Text; 
cmd.CommandText = @"SELECT soh.SalesOrderNumber,  
                            sod.ProductID  
                    FROM Sales.SalesOrderHeader AS soh 
                            INNER JOIN Sales.SalesOrderDetail AS sod 
                                   ON soh.SalesOrderID = sod.SalesOrderID 
                    WHERE soh.SalesOrderNumber = '" + txtSalesOrderNo.Text + "'";  
 
dtrSalesOrders = cmd.ExecuteReader();

 

這種通過動態拼接的方式組成的SQL語句即爲Ad hoc 查詢,與之對應的參數化查詢爲:

cmd.CommandType = CommandType.Text; 
cmd.CommandText = @"SELECT soh.SalesOrderNumber,  
                            sod.ProductID  
                    FROM Sales.SalesOrderHeader AS soh 
                            INNER JOIN Sales.SalesOrderDetail AS sod
                                ON soh.SalesOrderID = sod.SalesOrderID 
                    WHERE soh.SalesOrderNumber = @SalesOrderNo"; 
                    
cmd.Parameters.Add("@SalesOrderNo", SqlDbType.NVarChar, 50);  
cmd.Parameters["@SalesOrderNo"].Value = txtSalesOrderNo.Text; 
 
dtrSalesOrders = cmd.ExecuteReader();
 

當然,存儲過程是100%的參數化查詢,不管該存儲過程帶不帶參數,通常來說,生產環境中不應該有大量的Ad hoc 查詢,會導致Cpu利用率過高,系統性能下降,通常的解決辦法就是

在程序中改寫代碼,轉化成存儲過程的寫法,如果是沒辦法改寫客戶端的代碼,有以下幾種思路來緩解Cpu的壓力,但是不能100%奏效!

 

1:強制參數化

ALTER  DATABASE  AdventureWorks SET  PARAMETERIZATION FORCED 

2:修改實例配置

EXEC sp_configure  'show advanced options',1 
RECONFIGURE
 
EXEC sp_configure  'optimize for ad hoc workloads',1 
RECONFIGURE
 
希望這篇文章能理清ad hoc 查詢的概念!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章