SQL Server解惑——預定義語句與即席查詢區別


在SQL Server中預定義語句(Prepared Statement)與即席查詢(Ad Hoc Query)是啥區別呢? 其實官方文檔甚至沒有一個非常明確的定義說明,像Oracle、MySQL等其它數據庫,也沒有即席查詢這類概念。下面簡單總結一下即席查詢跟預定義語句。

 

即席查詢(Ad Hoc Query)

 

什么是即席查詢(Ad Hoc Query)呢?以單獨的SQL語句的形式執行的查詢就是即席查詢,一般這樣的SQL是硬編碼形式,動態執行的。例如,你在SSMS中查詢一個表中數據的SQL,但是存儲過程或函數中同樣的這么一個SELECT語句,就不叫即席查詢了,而是存儲過程/函數中的語句。

 

即席查詢有個特點就是SQL語句必須一模一樣,才能重用緩存的執行計划。

 

關於即席查詢的一些英文介紹(都是非官方資料)

 

An Ad-Hoc Query is a query that cannot be determined prior to the moment the query is issued. It is created in order to get information when need arises and it consists of dynamically constructed SQL which is usually constructed by desktop-resident query tools.

 

An Ad-Hoc Query is hard coded or the dynamically executed, and the cached plan can only be re-used for a near identical statement.

 

例如下面SQL就是一個即席查詢:

 

SELECT * FROM Person.Person WHERE BusinessEntityID=10;

 

另外,你在程序里面,拼接而成的SQL也是即席查詢。

 

 

預定義語句(Prepared Statement)

 

 

預定義語句指SQL語句中使用了占位符替換了實際值的SQL語句,例如,像參數化查詢這類SQL等等。這類語句可以重用,通過輸入不同的值,完成不同的操作。這個有點類似Oracle中使用綁定變量的SQL

 

 

關於預定義語句的一些英文介紹(都是非官方資料)

 

 

A prepared query is paramaterized and can be reused for a range of different inputs.

Queries which substitute place holders in place of actual values are called Prepared statements

 

A prepared query is paramaterized and can be reused for a range of different inputs

 

舉個例子,你在代碼里面的的這樣一個SQL語句,就是一個預定義語句。

 

 

command.CommandText = "SELECT * FROM dbo.Users WHERE UserID=@UserID AND Passowrd=@Passowrd";
 
 
command.Parameters.AddWithValue("@UserID", UserID);
 
command.Parameters.AddWithValue("@Passowrd", Passowrd);

 

 

那么下面,在SSMS中執行的SQL是即席查詢還是預定義語句呢?  

 

DECLARE @BusinessEntityID INT;
SET @BusinessEntityID=10;
SELECT * FROM Person.Person WHERE BusinessEntityID=@BusinessEntityID;

 

 

   如下驗證所示,你會發現這個SQL是即席查詢 

SELECT  cp.[usecounts] ,
        cp.[refcounts] ,
        cp.[cacheobjtype] ,
        CASE cp.[objtype]
          WHEN 'Proc'       THEN 'Stored procedure'
          WHEN 'Prepared'   THEN 'Prepared statement'
          WHEN 'Adhoc'      THEN 'Ad hoc query'
          WHEN 'ReplProc'   THEN 'Replication-filter-procedure'
          WHEN 'UsrTab'     THEN 'User table'
          WHEN 'SysTab'     THEN 'System table'
          WHEN 'Check'      THEN 'Check constraint'
          ELSE cp.[objtype]
        END AS [object_type] ,
        cp.[size_in_bytes] ,
        ISNULL(DB_NAME(qt.[dbid]), 'resourcedb') AS [db_name] ,
        qp.[query_plan] ,
        qt.[text]
FROM    sys.dm_exec_cached_plans cp
        CROSS APPLY sys.dm_exec_sql_text(cp.[plan_handle]) qt
        CROSS APPLY sys.dm_exec_query_plan(cp.[plan_handle]) qp
WHERE qt.text LIKE '%@BusinessEntityID%'
ORDER BY cp.[usecounts] DESC;
GO

 

clip_image001

 

這個是否有點顛覆了我們的認知? 照理說,這里的SQL使用了參數化查詢,應該是預定義語句(Prepared Statement)吧,但是在SSMS中執行這個SQL,就變成了即席查詢,但是在C#等語言中這樣運用的話,它就是預定義語句(Prepared Statement),很是糾結吧。原因也很簡單,如下所示,你修改一下參數@BusinessEntityID的值,運行一次,你會發現,SQL Server並沒有重用原先的執行計划,而是重新編譯了。所以它符合即席查詢的特征。 

DECLARE @BusinessEntityID INT;
SET @BusinessEntityID=12;
SELECT * FROM Person.Person WHERE BusinessEntityID=@BusinessEntityID;

 

 

clip_image002

 

 

在SSMS中執行下面SQL,繼續用上面SQL驗證,你會發現這個SQL語句的類型為預定義語句(Prepared Statement)

 

EXEC sp_executesql N'SELECT * FROM Person.Person WHERE BusinessEntityID=@BusinessEntityID', N'@BusinessEntityID INT', 10
GO

 

clip_image003

 

緩存的具體SQL如下:

 

(@BusinessEntityID INT)SELECT * FROM Person.Person WHERE BusinessEntityID=@BusinessEntityID

 

 

總結:

 

預定義語句(Prepared Statement)與即席查詢(Ad Hoc Query)有一個區別就是它是否有占位符(參數化查詢),而且能否在輸入不同的參數時,能否重用緩存的執行計划。

 

 

參考資料:

 

https://stackoverflow.com/questions/38072550/what-is-the-difference-between-ad-hoc-and-prepared-query-in-sql-server-plan-cach


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM