准备好的执行
ODBC API 会定义准备好的执行,以此来减少反复执行 Transact-SQL 语句时所需的分析和编译开销。该应用程序生成一个包含 SQL 语句的字符串,然后分两个阶段执行该语句。它通过调用一次 SQLPrepare 将该语句分析并编译为用数据库引擎执行的执行计划。随后它为每次执行准备好的执行计划调用 SQLExecute。这节省了每次执行的分析和编译开销。应用程序通常使用准备好的执行来重复执行相同的参数化 SQL 语句。
对于多数数据库中的需要执行三次或四次以上的语句,准备好的执行要比直接执行更快速。这主要是因为准备好的执行仅需编译一次语句,而直接执行的语句在每次执行时都需要编译。准备好的执行还可以减少网络流量,因为驱动程序在每次执行语句时都可以向数据源发送执行计划标识符及参数值,而不是整个 SQL 语句。
SQL Server 2000 和更高版本通过改进检测和重复使用 SQLExecDirect 的执行计划的算法,减少了直接执行和准备好的执行之间的性能差异。这使直接执行的语句也具备了准备好的执行的某些性能优势。有关详细信息,请参阅直接执行。
SQL Server 2000 和更高版本还提供针对准备好的执行的本机支持。针对 SQLPrepare 生成执行计划,然后在调用 SQLExecute 时执行。由于不要求 SQL Server 2000 和更高版本对 SQLPrepare 生成临时存储过程,所以在 tempdb 中不存在系统表的额外开销。
出于性能的原因,需推迟语句准备,直到调用 SQLExecute 或执行元属性操作(如 ODBC 中的 SQLDescribeCol 或 SQLDescribeParam)。这是默认行为。正在准备的语句如有任何错误,需等到执行该语句或执行元属性操作后才会发现。将 SQL Server Native Client ODBC 驱动程序特定的语句属性 SQL_SOPT_SS_DEFER_PREPARE 设置为 SQL_DP_OFF 可以关闭此默认行为。
对于延迟准备的情况,在调用 SQLExecute 之前调用 SQLDescribeCol 或 SQLDescribeParam 将生成额外的服务器往返。对于 SQLDescribeCol,驱动程序从查询中删除 WHERE 子句,并使用 SET FMTONLY ON 将查询发送到服务器,以获取查询所返回的第一个结果集中的列的说明。对于 SQLDescribeParam,驱动程序调用服务器以获取查询中的所有参数标记所引用的表达式或列的说明。此方法也存在一些限制,如无法解析子查询中的参数。
过多地将 SQLPrepare 用于 SQL Server Native Client ODBC 驱动程序将降低性能,特别是在连接到早期版本的 SQL Server 时。不应对执行一次的语句使用准备好的执行。对于执行一次的语句,准备好的执行要比直接执行慢,因为它需要多进行一次从客户端到服务器的网络往返。在早期版本的 SQL Server 中,它还生成临时存储过程。
在 SQL Server 2000 和更高版本中,或者在 SQL Server 的早期版本中,如果用于生成存储过程的选项处于活动状态,无法使用准备好的语句创建临时对象。如果启用此选项,准备好的语句将嵌入在调用 SQLExecute 时执行的临时存储过程。执行存储过程时创建的所有临时对象将在完成该过程时自动删除。如果用于生成准备存储过程的选项处于活动状态,以下两个示例都不会创建临时表 #sometable:
SQLPrepare(hstmt,
"CREATE TABLE #sometable(cola int, colb char(8))",
SQL_NTS);
SQLExecute(hstmt);
或
SQLPrepare(hstmt,
"SELECT * FROM Authors INTO #sometable",
SQL_NTS);
SQLExecute(hstmt);
某些早期 ODBC 应用程序一使用 SQLBindParameter 即使用 SQLPrepare。SQLBindParameter 不要求使用 SQLPrepare,它可与 SQLExecDirect 一同使用。例如,将 SQLExecDirect 与 SQLBindParameter 一同使用可以检索来自仅执行一次的存储过程的返回代码或输出参数。除非同一语句执行多次,否则请勿将 SQLPrepare 与 SQLBindParameter 一同使用。