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 查询的概念!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

原文地址:https://www.cnblogs.com/fly_zj/p/2496296.html