重用参数和执行计划

使用参数(包括 ADO、OLE DB 和 ODBC 应用程序中的参数标记)有助于重用执行计划。

安全说明安全说明

与将最终用户键入的值串联到字符串中,然后使用数据访问 API 方法、EXECUTE 语句或 sp_executesql 存储过程来执行该字符串相比,使用参数或参数标记来保存这些值更安全。

下面两个 SELECT 语句之间的唯一区别是 WHERE 子句中值不同:

SELECT * FROM AdventureWorks.Production.Product WHERE ProductSubcategoryID = 1;

SELECT * FROM AdventureWorks.Production.Product WHERE ProductSubcategoryID = 4;

这两个查询的执行计划之间的唯一区别是为比较 ProductSubcategoryID 列而存储的值。虽然目的是要让 SQL Server 总是认为语句实际生成了相同的计划并重复使用这些计划,但是 SQL Server 有时不能在复杂的 SQL 语句中检测到上述情况。

使用参数将常量与 SQL 语句分隔开有助于关系引擎识别重复计划。可以按下列方式使用参数:

  • 在 Transact-SQL 中,使用 sp_executesql

    DECLARE @MyIntParm INT
    SET @MyIntParm = 1
    EXEC sp_executesql
      N'SELECT * FROM AdventureWorks.Production.Product WHERE ProductSubcategoryID = @Parm',
      N'@Parm INT',
      @MyIntParm
    

    建议对动态生成 SQL 语句的触发器、Transact-SQL 脚本或存储过程使用此方法。

  • ADO、OLE DB 和 ODBC 使用参数标记。参数标记是问号 (?),在 SQL 语句中替代常量并绑定到程序变量。例如,可以在 ODBC 应用程序中执行下列操作:

    • 使用 SQLBindParameter 将整数变量绑定到 SQL 语句中的第一个参数标记。

    • 为变量赋整数值。

    • 执行语句,并指定参数标记 (?):

      SQLExecDirect(hstmt, 
        "SELECT * FROM AdventureWorks.Production.Product WHERE ProductSubcategoryID = ?",
        SQL_NTS);
      

      在应用程序中使用参数标记时,SQL Server 附带的 SQL Server Native Client OLE DB 访问接口和 SQL Server Native Client ODBC 驱动程序使用 sp_executesql 将语句发送到 SQL Server。

  • 设计使用参数的存储过程。

如果不将参数显式地置入应用程序的设计中,则也可以依赖 SQL Server 查询优化器使用 简单参数化 的默认行为自动参数化某些查询。另外,也可以通过将 ALTER DATABASE 语句的 PARAMETERIZATION 选项设置为 FORCED,强制查询优化器考虑将数据库中的所有查询参数化。有关详细信息,请参阅强制参数化

启用强制参数化后,仍会发生简单参数化。例如,根据强制参数化规则,无法将以下查询参数化:

SELECT * FROM Person.Address
WHERE AddressID = 1 + 2;

但根据简单参数化规则,可以将该查询参数化。尝试强制参数化失败后,仍将接着尝试简单参数化。