强制参数化

通过指定将数据库中的所有 SELECT、INSERT、UPDATE 和 DELETE 语句参数化,可以覆盖 SQL Server 的默认简单参数化行为,当然这可能会受到某些限制。在 ALTER DATABASE 语句中将 PARAMETERIZATION 选项设置为 FORCED 可启用强制参数化。强制参数化通过降低查询编译和重新编译的频率,可以提高某些数据库的性能。能够通过强制参数化受益的数据库通常是需要处理来自源(例如,销售点应用程序)的大量并发查询的数据库。

当 PARAMETERIZATION 选项设置为 FORCED 时,SELECT、INSERT、UPDATE 或 DELETE 语句中出现的任何文本值(无论以什么形式提交)都将在查询编译期间转换为参数。但下列查询构造中出现的文本例外:

  • INSERT...EXECUTE 语句。

  • 存储过程、触发器、或用户定义函数中包含的语句。SQL Server 已对这些例程重用了查询计划。

  • 已在客户端应用程序中参数化的预定义语句。

  • 包含 XQuery 方法调用的语句,此方法将出现在其参数通常都会参数化的上下文(例如,WHERE 子句)中。如果在方法所在的上下文中方法的参数不参数化,则语句的其余部分将参数化。

  • Transact-SQL 游标内的语句。(API 游标内的 SELECT 语句将参数化。)

  • 不推荐使用的查询构造。

  • 在 ANSI_PADDING 或 ANSI_NULLS 设置为 OFF 的上下文中执行的任何语句。

  • 包含 2,097 个以上的可参数化文字的语句。

  • 引用变量的语句,例如,WHERE T.col2 >= @bb。

  • 包含 RECOMPILE 查询提示的语句。

  • 包含 COMPUTE 子句的语句。

  • 包含 WHERE CURRENT OF 子句的语句。

另外,未参数化下面的查询子句。注意,在这些情况下只有子句未参数化。同一个查询中的其他子句或许可以进行强制参数化。

  • 任何 SELECT 语句的 <select_list>。其中包括子查询的 SELECT 列表和 INSERT 语句中的 SELECT 列表。

  • IF 语句中出现的子查询 SELECT 语句。

  • 查询的 TOP、TABLESAMPLE、HAVING、GROUP BY、ORDER BY、OUTPUT...INTO 或 FOR XML 子句。

  • OPENROWSET、OPENQUERY、OPENDATASOURCE、OPENXML 或任意 FULLTEXT 运算符的直接参数或作为子表达式的参数。

  • LIKE 子句的模式和 escape_character 参数。

  • CONVERT 子句的样式参数。

  • IDENTITY 子句中的整数常量。

  • 使用 ODBC 扩展语法指定的常量。

  • 可折叠常量表达式,它们是 +、-、*、/ 和 % 运算符的参数。在考虑是否能够强制参数化时,SQL Server 将认为满足下列条件之一的表达式是可折叠常量表达式:

    • 表达式中没有列、变量、或子查询。

    • 表达式包含 CASE 子句。

    有关可折叠常量表达式的详细信息,请参阅排除查询性能不佳的故障:基数估计过程中的常量折叠和表达式计算

  • 查询提示子句的参数。这些参数包括 FAST 查询提示的 number_of_rows 参数、MAXDOP 查询提示的 number_of_processors 参数以及 MAXRECURSION 查询提示的 number 参数。

参数化在单条 Transact-SQL 语句内发生。即,批处理中的单条语句将参数化。在编译之后,已参数化的查询将在它最初提交时所在的批的上下文中执行。如果缓存了查询的执行计划,则可以通过引用 sys.syscacheobjects 动态管理视图的 sql 列来确定此查询是否已参数化。如果查询已参数化,则参数的名称和数据类型将出现在此列中已提交的批的文本前面。例如,(@1 tinyint)。有关缓存查询计划的信息,请参阅执行计划的缓存和重新使用

注意注意

参数名称是任意的。用户或应用程序不必拘泥于特定的命名顺序。另外,下面的内容可能会因 SQL Server 版本以及 Service Pack 升级版本而异:参数名称、要参数化的文字的选择以及参数化文本中的空格。

参数数据类型

当 SQL Server 参数化文本时,参数将转换为下列数据类型:

  • 其大小适合 int 数据类型的整数文本将参数化为 int。对于较大的整数文本,如果它是包含任意比较运算符(包括 <、<=、=、!=、>、>=、!<、!>、<>、ALL、ANY、SOME、BETWEEN 和 IN)的谓词的组成部分,则将参数化为 numeric(38,0)。如果它不是包含比较运算符的谓词的组成部分,则此类文本将参数化为 numeric,其精度仅够表示其大小,并且没有小数位。

  • 如果定点数值是涉及比较运算符的谓词的组成部分,则此类数值将参数化为 numeric,其精度为 38,并且小数位数仅够表示其大小。如果定点数值不是涉及比较运算符的谓词的组成部分,则此类数值将参数化为 numeric,其精度和小数位数仅够表示其大小。

  • 浮点数值将参数化为 float(53)。

  • 如果非 Unicode 字符串文本在 8000 个字符以内,将参数化为 varchar(8000),如果多于 8000 个字符,则参数化为 varchar(max)。

  • 如果 Unicode 字符串文本在 4000 个 Unicode 字符以内,将参数化为 nvarchar(4000),如果多于 4000 个字符,则参数化为 nvarchar(max)。

  • 如果二进制文本在 8000 字节以内,将参数化为 varbinary(8000)。如果多于 8000 字节,则转换为 varbinary(max)。

  • Money 类型的文本,将参数化为 money。

强制参数化使用指南

当把 PARAMETERIZATION 选项设置为 FORCED 时注意以下事项:

  • 强制参数化实际上是在对查询进行编译时将查询中的文本常量更改为参数。因此,查询优化器可能会选择不太理想的查询计划。尤其是查询优化器不太可能将查询与索引视图或计算列索引相匹配。它还可能会选择对分区表和分布式分区视图执行的不太理想的查询计划。强制参数化不能用于高度依赖索引视图和计算列索引的环境。通常,PARAMETERIZATION FORCED 选项应仅供有经验的数据库管理员在确定这样做不会对性能产生负面影响之后使用。

  • 一旦(上下文中正在执行查询的)数据库中的 PARAMETERIZATION 选项设置为 FORCED,则引用了多个数据库的分布式查询即可进行强制参数化。

  • PARAMETERIZATION 选项设置为 FORCED 将刷新数据库的计划缓存中的所有查询计划,当前正在编译、重新编译或执行的查询除外。在设置更改时正在编译或执行的查询计划将在下次执行时参数化。

  • 设置 PARAMETERIZATION 选项是一项联机操作,它不需要数据库级别的排他锁。

  • 当将 SQL Server 数据库兼容性设置为 80,或将早期实例上的数据库附加到 SQL Server 2005 或更高版本的实例时,将禁用强制参数化(设置为 SIMPLE)。

  • 在重新附加或还原数据库时,PARAMETERIZATION 选项的当前设置将保留。

您可以指定对单个查询和其他语法相同只有参数值不同的查询进行简单参数化,以覆盖强制参数化行为。相反,即使数据库中禁用了强制参数化,您也可以指定仅对一组语法相同的查询进行强制参数化。计划指南具有此用途。有关详细信息,请参阅使用计划指南指定查询参数化行为

注意注意

当 PARAMETERIZATION 选项设置为 FORCED 时,错误消息的报告可能与简单参数化有所区别:对于同样的情况,在简单参数化下可能报告的消息较少,而现在则可能报告多条错误消息,并且可能无法准确报告出现错误的行号。