引言
该堆栈的顶部是 API 或对象库层应用程序通过对象库公开的 API 函数或接口连接到 Microsoft? SQL Server用于访问 SQL Server 的 API 示例包括 ODBC 和 DBLibrary用于访问 SQL Server 的对象库示例包括 OLE DBADO 和 ADONET由于 ADO 最终使用 OLE DB 与服务器通信因此 Windows 应用程序在与 SQL Server 通信时实际上只使用两个常用的对象库即 OLE DB 和 ADONET由于通过 ADO 或 ADONET 进行连接通常比通过 ODBC 进行连接更普遍(但 SQL Server 的查询分析器和企业管理器仍通过 ODBC 进行连接)因此本文将从 ADO/OLE DB 和 ADONET 的角度介绍 SQL Server 连接体系结构的客户端如今大多数应用程序均通过对象库(而非 ODBC 或类似 API)连接到 SQL Server
ADO 和 OLE DB
OLE DB 客户端(也称作使用者)通过客户端提供程序与服务器以及其他后端程序进行通信此提供程序是一组 COM 组件(一个或多个)用于将应用程序请求转换为网络进程间通信 (IPC) 请求在使用 SQL Server 的情况下最常用的 OLE DB 提供程序是 SQLOLEDB它是 Microsoft 为 SQL Server 提供的 OLE DB 提供程序SQLOLEDB 随附于 SQL Server 中并作为 Microsoft 数据访问组件 (MDAC) 库的一部分安装
为了使用 ADO 与 SQL Server 进行通信应用程序首先使用 Connection 对象建立与服务器的连接ADO 的 Connection 对象接受一个连接字符串该字符串指定要使用的 OLE DB 提供程序以及传递给它的参数如果应用程序使用 SQLOLEDB 提供程序连接到 SQL Server则该字符串中将显示SQLOLEDB
ADO 应用程序还可以通过 ODBC 连接到 SQL Server为此应用程序将使用适用于 ODBC 的 OLE DB 提供程序并指定在其连接字符串中引用目标 SQL Server 的 ODBC 数据源这种情况下应用程序与 OLE DB 进行通信同时 ODBC 的 OLE DB 提供程序调用相应的 ODBC API以便与 SQL Server 进行会话
ADONET
ADONET 应用程序通常使用 NET Framework Data Provider for SQL Server 连接到 SQL Server该本机提供程序使 ADONET 对象能够与 SQL Server 直接进行通信通常应用程序使用 SqlConnection 对象建立连接然后使用 SqlCommand 对象向服务器发送命令并接收服务器返回的结果SqlDataAdapter 和 SqlDataReader 类通常与 SqlCommand 一起使用以便通过托管的代码应用程序与 SQL Server 进行交互
通过 OleDbConnection 类ADONET 应用程序还可以使用 SQLOLEDB OLE DB 提供程序与 SQL Server 进行交互此外它们可以通过 OdbcConnection 类使用 ODBC 访问 SQL Server因此仅通过托管代码您就有三种不同的方法从应用程序访问 SQL Server从故障排除的角度而言了解这些方法是非常有用的因为它可以帮助您将遇到的与连接相关的问题归结到特定的数据访问层或库
客户端 NetLibrary
该堆栈中的下一层是 NetLibraryNetLibrary 在 API 或对象库(应用程序使用它与 SQL Server 进行通信)与网络协议(用于与网络交换数据)之间提供了一个通道SQL Server 为所有主要的网络协议提供了 NetLibrary这些库以透明方式将客户端发出的请求发送到 SQL Server并将服务器发出的响应返回给客户端可以使用 SQL Server 的客户端网络实用程序配置适用于特定客户端的 NetLibrary支持的客户端协议包括 TCP/IP命名管道NWLink多协议 (RPC) 和其他一些协议
尤其值得一提的 NetLibrary 是共享内存 NetLibrary顾名思义该 NetLibrary 使用 Windows 的共享内存功能在 SQL Server 客户端与服务器之间进行通信显然这意味着客户端与服务器必须位于同一台物理计算机上
由于它能够绕过物理网络堆栈因此共享内存 NetLibrary 要比其他 NetLibrary 快得多对共享内存区域的访问受到同步对象的保护因此客户端与服务器之间的通信速度主要受限于 Windows 对内核对象进行调度的能力以及进程与共享内存区域之间进行数据复制的能力
可以在连接时将某个时间段或(本地)指定为您的计算机名来指示使用共享内存 NetLibrary也可以在连接时为计算机\实例名加上前缀 lpc:来指示要使用共享内存 NetLibrary
注意即使连接到同一台计算机上的 SQL Server共享内存 NetLibrary 也未必就是最佳的连接选项在某些情况下客户端与服务器之间的直接连接可能限制它的扩展性与应用程序整体体系结构中的其他元素一样应始终对给定技术解决方案进行全面的测试然后才能判断它是否有良好的扩展性以及是否比其他方法更快
连接
客户端进行连接时SQL Server 的用户模式计划程序 (UMS) 组件将它指定给特定的计划程序启动时SQL Server 为系统上的每个 CPU 创建一个单独的 UMS 计划程序当客户端连接到服务器时这些客户端将指定给具有最少连接数的计划程序连接后客户端将不会更换计划程序 它将始终受到指定计划程序的控制直到连接断开
这对与服务器建立多个连接的应用程序很重要如果应用程序性能较差或无法在它的多个连接上平均分配工作则在该应用程序的某些连接之间可能造成不必要的 CPU 资源争用而其他连接实际上却处于空闲状态
例如应用程序与双处理器计算机上运行的 SQL Server 建立了四个连接连接 和 隶属于处理器 连接 和 隶属于处理器 如果应用程序的大部分工作通过连接 和 执行则这两个连接将争用 CPU 而 CPU 实际上可能仍处于空闲状态这种情况下应用程序只能断开某些连接或重新连接某些连接并希望连接 和 隶属于不同的 CPU (连接时无法指定处理器隶属关系)或在它的连接上重新分配工作负荷以便每个连接的工作负荷更加均衡当然后一种情况要远好于前一种情况
连接内存
SQL Server 为客户端请求的每个连接保留三个数据包缓沖区每个缓沖区的大小取决于 sp_configure 存储过程指定的默认网络数据包大小如果默认网络数据包大小小于 KB则这些数据包的内存将由 SQL Server 的缓沖池提供否则该内存将由 SQL Server 的 MemToLeave 区域分配
值得一提的是NET Framework Data Provider for SQL Server 的默认网络数据包大小为 KB因此与托管代码客户端连接关联的缓沖区通常由 SQL Server 的 MemToLeave 区域提供而典型的 ADO 应用程序却不同它们的默认数据包大小为 KB因此缓沖区将由 SQL Server 缓沖池分配
事件
连接后的客户端请求通常分为两种广泛类别语言事件和远程过程调用尽管还存在其他类别但大多数由 SQL Server 客户端发送到服务器的请求由以下两种类型之一构成语言事件是从客户端发送到服务器的 一组 TSQL例如如果调用 ADO Command 对象(其 CommandText 属性设置为 TSQL 查询CommandType 属性设置为 adCmdText)的 Execute 方法则查询将作为语言事件提交给服务器同样如果将 CommandType 设置为 adCmdTable 并调用 Execute 方法则 ADO 将生成一个内部查询(它将选择 CommandText 属性标识的表中的所有列)并将它作为语言事件提交给服务器另一方面如果将 CommandType 设置为 adStoredProc则调用 Execute 将使 ADO 向服务器提交一个远程过程调用请求以执行 CommandText 属性中列出的存储过程
为何要关心将请求作为语言事件还是作为 RPC 提交给服务器呢?通常这是因为 RPC 的功能更为出色特别是在重复调用具有不同筛选值的同一查询时尽管 SQL Server 可以自动将普通的语言事件请求参数化但这种能力非常有限它从不尝试自动将某些类型的查询参数化这可能会导致基本相同的查询产生不同的执行从而只因为这些不同的执行提供不同的值而导致在服务器上白白浪费计划编译的成本这通常不是您所希望的结果 您希望针对查询的第一次执行编译一个新的计划然后将该计划重复用于具有不同参数的执行
而 RPC 则通过显式参数化查询(而不是依赖服务器参数化查询)来支持计划重复使用为过程的第一次执行生成一个计划后随后的执行将自动重复使用该计划即使它们提供的参数值不同与通过语言事件调用存储过程相比使用 RPC 调用存储过程不仅节省了计划编译所需的执行时间和 CPU 资源还增强了 SQL Server 内存资源的利用率因为它避免了冗余执行计划所浪费的内存
在执行动态 TSQL 时通常首选 sp_executesql 而不是 EXEC() 也出于同样的原因Sp_executesql 的工作方式是使用指定的查询创建一个存储过程然后使用提供的参数调用它与 EXEC() 不同sp_executesql 提供了一个允许您参数化动态 TSQL 并支持计划重复使用的机制使用 sp_executesql 执行的动态查询比使用 EXEC() 的查询能够在更大程度上避免不必要的编译和资源消耗
TDS
从客户端发送到 SQL Server 的 RPC语言事件和其他类型的请求被格式化为称作表格数据流 (TDS) 的 SQL Server 特定数据格式TDS 是 SQL Server 客户端和服务器之间使用的语言对于它的确切格式将不作介绍但是如果客户端要与 SQL Server 进行通信就必须使用 TDS
目前SQL Server 支持三种版本的 TDSTDS (适用于 SQL 客户端)TDS (适用于 SQL Server 客户端)和 TDS (适用于 SQL Server 和 客户端)完全支持所有 SQL Server 功能的版本只有 TDS 其他版本保持向后兼容
服务器端 NetLibrary
在服务器端客户端请求最初由 SQL Server 为侦听特定网络协议而建立的侦听器接收这些侦听器由服务器上的网络库以及服务器端<