Microsoft SQL Server 2000 分布式查询:OLE DB 连接

减小字体 增大字体 作者:佚名  来源:本站整理  发布时间:2009-03-16 14:00:08
 

摘要:本文描述了 Microsoft SQL Server 2000 查询处理器如何与 OLE DB 提供程序进行交互以实现分布式和异类查询。它面向的读者主要是 OLE DB 提供程序开发人员,并假设读者对 OLE DB 规范有深入的了解。

目录

简介
概述和术语
OLE DB 提供程序交互阶段
查询执行方案
总结
附录 A:SQL Server 采用的 OLE DB 接口
附录 B: 用于生成远程查询的 SQL 子集

简介

本文描述了 Microsoft® SQL Server™ 2000 查询处理器如何与 OLE DB 提供程序进行交互以实现分布式和异类查询。它面向的读者主要是 OLE DB 提供程序开发人员,并假设读者对 OLE DB 规范有深入的了解。本文重点在于描述 SQL Server 查询处理器和 OLE DB 提供程序之间的 OLE DB 接口,而不是分布式查询功能本身。有关分布式查询功能的完整描述,请参阅 SQL Server Books Online。

概述和术语

在 Microsoft SQL Server 2000 中,分布式查询允许 SQL Server 用户访问基于 SQL Server 的服务器以外的数据(位于其他运行 SQL Server 的服务器或是具有 OLE DB 接口的其他数据源中)。OLE DB 提供了统一的方式来访问异类数据源中的列表数据。

在本文中,分布式查询是指任何引用了一个或多个外部 OLE DB 数据源中表或行集的 SELECT、INSERT、UPDATE 或 DELETE 语句。

远程表是指存储于 OLE DB 数据源中并且不在执行查询的 SQL Server 所在服务器上的表。一个分布式查询可以访问一个或多个远程表。

OLE DB 提供程序类别

根据 OLE DB 提供程序在 SQL Server 的分布式查询中的功能,我们将它们划分为如下类别。根据定义,它们并非互相排斥;某种提供程序可能属于一个或多个类别:

  • SQL 命令提供程序

  • 索引提供程序

  • 简单表提供程序

  • 非 SQL 命令提供程序

SQL 命令提供程序

凡是以 SQL 标准语法(SQL Server 认可)支持 Command 对象的提供程序,都属于此类别。下面是 OLE DB 提供程序被 SQL Server 视为 SQL 命令提供程序的必要条件:

  • 提供程序必须支持 Command 对象及其所有强制 OLE DB 接口:ICommand、ICommandText、IColumnsInfo、ICommandProperties 和 IAccessor。

  • 提供程序支持的 SQL 语法必须至少是 SQL 子集。提供程序必须通过 DBPROP_SQLSUPPORT 属性来报告语法。

SQL 命令提供程序的示例为:Microsoft OLE DB Provider for SQL Server 和 Microsoft OLE DB Provider for ODBC。

索引提供程序

索引提供程序支持并提供与 OLE DB 对应的索引,同时还允许基于索引对基本表执行查找。下面是 OLE DB 提供程序被 SQL Server 视为索引提供程序的必要条件:

  • 提供程序必须以 TABLES、COLUMNS 和 INDEXES 架构行集支持 IDBSchemaRowset 接口。

  • 提供程序必须支持通过 IOpenRowset 打开索引中的行集(通过指定索引名和相应的基本表名称)。

  • Index 对象必须支持其所有的强制接口:IRowset、IRowsetIndex、IAccessor、IColumnsInfo、IRowsetInfo 和 IConvertTypes。

  • 对带索引基本表打开的行集(通过使用 IOpenRowset)必须支持 IRowsetLocate 接口,以便根据书签在行上定位。

如果一个 OLE DB 提供程序满足以上条件,用户可以设置提供程序选项 Index As Access Path,以允许 SQL Server 使用提供程序的索引来执行查询。默认情况下,除非该选项已被设置,否则 SQL Server 不会尝试使用提供程序的索引。

注意:   SQL Server 支持多个影响 SQL Server 访问 OLE DB 提供程序的方法的选项。可以使用 SQL Server 企业管理器中的“链接服务器属性”对话框来设置这些选项。

简单表提供程序

简单表提供程序通过 IOpenRowset 接口来表现根据基本表打开行集的方式。这些提供程序既不是 SQL 命令提供程序也不是索引提供程序;而是 SQL Server 分布式查询所能处理的提供程序中最简单的一类。

对于此类提供程序,SQL Server 仅能在分布式查询运行过程执行表扫描操作。

非 SQL 命令提供程序

该类提供程序支持 Command 对象及其所有强制接口,但不支持 SQL Server 认可的 SQL 标准语法。

非 SQL 命令提供程序的两个示例是:Microsoft OLE DB Provider for Indexing Service 和 Microsoft Windows NT® Active Directory™ Service Interfaces (ADSI) OLE DB Provider。

Transact-SQL 子集

如果提供程序支持所需的 OLE DB 接口,下列 Transact-SQL 语句类别都可以用于分布式查询。

  • 除了将远程表作为目的表的 SELECT INTO 语句外,其他所有的 SELECT 语句都可以使用。

  • 如果提供程序支持插入操作所需的接口,INSERT 语句可以用于远程表。有关 INSERT 语句的 OLE DB 要求的详细信息,请查阅本文后面的 INSERT 语句

  • 如果提供程序满足 OLE DB 接口在特定表上的要求,UPDATE 和 DELETE 语句也可以用于远程表。有关更新或删除远程表时 OLE DB 接口必须满足的要求和条件,请参阅本文后面的 UPDATE 和 DELETE 语句

游标支持

如果提供程序支持所需的 OLE DB 功能,则分布式查询支持快照和键集两种游标。分布式查询不支持动态游标。用户请求的分布式查询的动态游标将自动降级为键集游标。

快照游标在游标打开时被写入,而且结果集保持不变;对基本表的更新、插入和删除操作不会反映到游标中。

键集游标在游标打开时被写入,而且结果集在游标的整个生存期中保持不变。但是,如果更新或删除基本表中的行,当访问这些行时,能够在游标中看到变化。如果对基本表的插入操作可能影响游标成员,则这种变化则是不可见的。

如果提供程序满足更新和删除远程表的条件,则可以通过使用分布式查询中定义的游标以及对远程表的引用来更新和删除远程表,例如:table UPDATE DELETE <远程表> WHERE CURRENT OF <游标名称>。有关详细信息,请参阅本文后面的 UPDATE 和 DELETE 语句

支持键集游标的要求

如果满足所有 Transact-SQL 语法的条件,而且满足以下两种情况之一,那么在分布式查询中就支持键集游标:

  • 在查询中,OLE DB 提供程序支持所有远程表上的可重用书签。可重用书签可以从给定表的某个行集中隐去,然后用于同一表中的其他行集上。对可重用书签的支持是通过 IDBSchemaRowset 的 TABLES_INFO 架构行集来指定的,方法是将 BOOKMARK_DURABILITY 列设置为 BMK_DURABILITY_INTRANSACTION 或某种更高的持久性。

  • 所有的远程表都通过 IDBSchemaRowset 接口的 INDEXES 行集来列出唯一键。应该存在一个索引项,其中的 UNIQUE 列设置为 VARIANT_TRUE。

包含 OpenQuery 函数的分布式查询不支持键集游标。

支持可更新键集游标的要求

通过在分布式查询上定义的键集游标,可以更新或删除远程表,例如:UPDATE DELETE <远程表> WHERE CURRENT OF <游标名称>。下面是在分布式查询中允许使用可更新游标的条件:

  • 如果提供程序也满足对远程表进行更新和删除操作的条件,就允许使用可更新游标。有关详细信息,请参阅本文后面的 UPDATE 和 DELETE 语句

  • 所有的可更新键集游标操作必须位于使用可复读或更高的隔离级别的用户定义事务中。此外,提供程序必须以 ITransactionJoin 接口支持分布式事务处理。

OLE DB 提供程序交互阶段

所有分布式查询的执行方案都有六种操作:

  • 建立连接和检索属性操作,指定 SQL Server 连接 OLE DB 提供程序的方法以及将用到提供程序的哪些属性。

  • 表名解析和检索元数据操作,指定 SQL Server 将远程表名称(指定时使用两种方法之一:基于链接服务器的名称或特殊名称)解析为提供程序中相应数据对象的方法。这也包括 SQL Server 为编译和优化分布式查询从提供程序检索的表元数据。

  • 事务管理操作,指定所有与 OLE DB 提供程序的事务相关的交互。

  • 数据类型处理操作,该操作指定在执行分布式查询过程中,当 SQL Server 从 OLE DB 提供程序获得数据或向其导出数据时 SQL Server 处理 OLE DB 数据类型的方法。

  • 错误处理操作,指定 SQL Server 使用从提供程序获得的扩展错误信息的方法。

  • 安全性操作,指定 SQL Server 安全性和提供程序安全性的交互方式。

建立连接和检索属性

SQL Server 使用 OPENROWSET 功能支持两种远程数据对象命名协议:基于链接服务器的四段式名称和特殊名称。

基于链接服务器的名称

链接服务器是对 OLE DB 数据源的抽象。基于链接服务器的名称分为四段:<链接服务器>.<目录>.<架构>.<对象>,其中 <链接服务器> 是链接服务器的名称。SQL Server 将 <链接服务器> 视为 OLE DB 提供程序和连接属性(用于向提供程序标识数据源)的来源。其他三个名称段被 OLE DB 数据源解释为对特定远程表的标识。

特殊名称

特殊名称是基于 OPENROWSET 或 OPENDATASOURCE 函数的名称。它包括在分布式查询中每次引用远程表时的所有连接信息(包括所使用的 OLE DB 提供程序、用于标识数据源的属性、用户 ID 和密码)。

默认情况下,只允许系统管理员使用特殊名称。要使用基于 OLE DB 提供程序的特殊名称,应将提供程序的 DisallowAdhocAccess 选项设置为 0。

如果使用链接服务器名称,SQL Server 将在链接服务器定义中为 OLE DB 提供程序提取提供程序的名称和初始化属性。如果使用特殊名称,SQL Server 将从 OPENROWSET 函数的参数中提取相同的信息。

有关使用四段式名称建立链接服务器和基于特殊名称的语法的详细说明,请参阅 SQL Server Books Online。

连接 OLE DB 提供程序

以下是 SQL Server 连接 OLE DB 提供程序时执行的高级步骤。

  1. SQL Server 创建数据源对象。

    SQL Server 使用提供程序的 ProgID 来建立数据源对象 (DSO) 的实例。ProgID 被指定为链接服务器配置信息的 provider_name 参数,或在使用特殊名称时被指定为 OPENROWSET 函数的第一个参数。

    SQL Server 通过 OLE DB 服务组件接口 IDataInitialize 创建提供程序的 DSO 实例。这使服务组件管理器可以在提供程序的本地功能上集成其服务(例如回滚和支持更新)。另外,通过 IDataInitialize 建立提供程序的实例还允许 OLE DB 服务组件为它们提供连接池,这样可减少连接和初始化的开销。

    在 SQL Server 的进程中还是在一个独立的进程中创建给定提供程序的实例,可以根据需要进行配置。在独立的进程中创建实例能够保护 SQL Server 进程免受提供程序故障的影响。但同时还存在着与在 SQL Server 进程外组织 OLE DB 调用有关的性能开销。通过设置提供程序选项 Allow In Process,可以将提供程序配置为进程内实例或进程外实例。有关设置提供程序选项的详细信息,请参阅 SQL Server Books Online。

    要学习更多有关 OLE DB 服务组件和建立会话池的知识,请参阅提供程序的 OLE DB 文档。

  2. 初始化数据源。

    创建 DSO 之后,如果服务器的配置选项 remote login timeout 大于 0,IDBProperties 接口将设置 DBPROP_INIT_TIMEOUT 初始化属性;该属性为必需的属性。

    如果在链接服务器定义或 OPENROWSET 函数的第二个参数中指定或隐含了下列属性,则它们将被设置:

    • DBPROP_INIT_PROVIDERSTRING

    • DBPROP_INIT_DATASOURCE

    • DBPROP_INIT_LOCATION

    • DBPROP_INIT_CATALOG

    • DBPROP_AUTH_USERID

    • DBPROP_AUTH_PASSWORD

    设置了这些属性后,将调用 IDBInitialize::Initialize 以指定的属性初始化 DSO。

  3. SQL Server 收集特定提供程序的信息。

    SQL Server 将收集若干用于分布式查询执行中的提供程序属性;这些属性将通过调用 IDBProperties::GetProperties 来检索。这些属性全都是可选的;但是,对所有相关属性的支持将允许 SQL Server 充分利用提供程序的功能。例如,在确定 SQL Server 是否能够向提供程序发送查询时,需要使用 DBPROP_SQLSUPPORT。如果提供程序不支持该属性,SQL Server 就不能将远程提供程序用作 SQL 命令提供程序,即使它是一个 SQL 命令提供程序。在下表(表 1)中,“默认值”列列出了在提供程序不支持该属性时 SQL Server 所采用的值。

表 1:SQL Server OLE-DB 提供程序采用的属性

属性默认值用法
DBPROP_DBMSNAME用于错误信息。
DBPROP_DBMSVER用于错误信息。
DBPROP_PROVIDERNAME用于错误信息。
DBPROP_PROVIDEROLEDBVER1.5用于确定 2.0 功能的可用性。
DBPROP_CONCATNULLBEHAVIOR用于确定提供程序的 NULL 连接行为是否与 SQL Server 一致。
DBPROP_NULLCOLLATION只有在 NULLCOLLATION 符合 SQL Server 的 Null 排序规则时才允许排序/使用索引。
DBPROP_OLEOBJECTS确定提供程序是否支持大数据对象列的结构化存储接口。
DBPROP_STRUCTUREDSTORAGE确定支持哪种用于大对象类型的结构化存储接口( ILockBytes、Istream 和 ISequentialStream 三种接口之一)。
DBPROP_MULTIPLESTORAGEOBJECTSFalse确定是否支持同时打开一个以上的大对象列。
DBPROP_SQLSUPPORT确定是否能够向提供程序发送 SQL 查询。
DBPROP_CATALOGLOCATIONDBPROPVAL_CL_START用于构造多段表名。
SQLPROP_DYNAMICSQLFalseSQL Server 特有的属性:如果返回 VARIANT_TRUE,则指示参数标记 '?' 可以用于参数化查询执行。
SQLPROP_NESTEDQUERIESFalseSQL Server 特有的属性:如果返回 VARIANT_TRUE,则指示提供程序在 FROM 子句中支持嵌套的 SELECT 语句。
SQLPROP_GROUPBYFalseSQL Server 特有的属性:如果返回 VARIANT_TRUE,则指示提供程序支持在 SELECT 语句中使用 GROUP BY 子句(如 SQL-92 标准所规定的一样)。
SQLPROP_DATELITERALSFalseSQL Server 特有的属性:如果返回 VARIANT_TRUE,则指示提供程序支持各 SQL Server Transact-SQL 语法所规定的日期时间文字。
SQLPROP_ANSILIKEFalseSQL Server 特有的属性:该属性对支持 SQL-Minimum 级别的提供程序比较有意义,并且它支持各 SQL-92 entry 级别所规定的 LIKE 运算符(使用 '%' 和 '_' 作为通配符)。
SQLPROP_SUBQUERIESFalseSQL Server 属性:该属性对支持 SQL-Minimum 级别的提供程序比较有意义。它指示提供程序支持 SQL-92 Entry 级别所规定的子查询。包括 SELECT 序列和 WHERE 子句中的子查询(支持相关子查询以及 IN、EXISTS、ALL 和 ANY 运算符)。
SQLPROP_INNERJOINFalseSSQL Server 特有的属性:该属性对支持 SQL-Minimum 级别的提供程序比较有意义。它指示支持在 FROM 子句中使用多表的联接。

下面是从 IDBInfo::GetLiteralInfo 检索到的三个文字:DBLITERAL_CATALOG_SEPARATOR、DBLITERAL_SCHEMA_SEPARATOR(用于根据给定的目录、架构和对象名构造完整的对象名称)和 DBLITERAL_QUOTE(用于引用发送到提供程序的 SQL 查询中的标识符名称)。

如果提供程序不支持分隔符文字,SQL Server 将使用句点 (.) 作为默认的分隔符字符。如果提供程序只支持目录分隔符字符而不支持架构分隔符字符,则 SQL Server 将把目录分隔符字符也作为架构分隔符字符使用。如果提供程序不支持 DBLITERAL_QUOTE,SQL Server 将使用单引号 (') 作为引用字符。

注意:    如果提供程序的名称分隔符文字和这些默认值不匹配,提供程序必须使用 IDBInfo 将它们公开,以便 SQL Server 通过四段式名称访问它的表。如果没有将这些文字公开,那么对于这样的提供程序将只能使用传递查询。

表名解析和元数据检索

SQL Server 将分布式查询中给定的远程表名称解析为 OLE DB 数据源中的特定表或视图。基于链接服务器的和特殊的命名架构都将导致提供程序将名称解释为三段式名称。在使用基于链接服务器的名称时,四段式名称的后三部分形成目录、架构和对象名。在使用特殊名称时,OPENROWSET 函数的第三个参数指定了说明目录、架构和对象名的三段式名称。目录和架构名称中可以有一个为空值或全部为空值。(当目录名和架构名为空时,四段式名称将变成:<服务器名称>...<对象名称>。)在此情况下,SQL Server 搜索架构行集表时将使用 NULL 作为对应的值。

SQL Server 使用的名称解析规则和元数据检索的步骤取决于提供程序是否支持 Session 对象的 IDBSchemaRowset 接口。

如果支持 IDBSchemaRowset,则使用 IDBSchemaRowset 接口中的 TABLES、COLUMNS、INDEXES 和 TABLES_INFO 架构行集。(TABLES_INFO 架构行集在 OLE DB 2.0 中定义。)SQL Server 通过限制 IDBSchemaRowset 接口返回的架构行集来寻找与特定远程表名称部分匹配的架构行。下面是与提供程序支持的架构行集限制有关的规则,以及 SQL Server 使用这些规则来检索远程表元数据的方法:

  • 对 TABLE_NAME 和 COLUMN_NAME 列的限制总是必要的。

  • 如果提供程序支持对 TABLE_CATALOG(或 TABLE_SCHEMA)的限制,SQL Server 将使用对 TABLE_CATALOG(或 TABLE_SCHEMA)的限制。如果在远程表名中没有指定目录(或架构)名称,则使用 NULL 值作为相应的限制值。如果指定了目录(或架构)名称,提供程序必须支持对 TABLE_CATALOG(或 TABLE_SCHEMA)的相应限制。

  • 提供程序必须全部支持对 TABLES 和 COLUMNS 中的 TABLE_SCHEMA 列的限制,或者全部不支持。提供程序必须全部支持对 TABLES 和 COLUMNS 的目录名称限制,或者全部不支持。

  • 如果支持 INDEXES 上的任何限制,提供程序必须全部支持对 TABLES 和 INDEXES 的架构限制,或者全部不支持。提供程序必须全部支持对 TABLES 和 INDEXES 行集的目录名限制,或者全部不支持。

从 TABLES 架构行集中,通过按上述规则设置限制,SQL Server 可检索 TABLE_CATALOG、TABLE_SCHEMA、TABLE_NAME、TABLE_TYPE 和 TABLE_GUID 列。

从 COLUMNS 架构行集中,SQL Server 可检索 TABLE_CATALOG、TABLE_SCHEMA、TABLE_NAME、COLUMN_NAME、COLUMN_GUID、ORDINAL_POSITION、COLUMN_FLAGS、IS_NULLABLE、DATA_TYPE、TYPE_GUID、CHARACTER_MAXIMUM_LENGTH、NUMERIC_PRECISION 和 NUMERIC_SCALE 列。COLUMN_NAME、DATA_TYPE 和 ORDINAL_POSITION 必须返回有效的非空值。如果 DATA_TYPE 是 DBTYPE_NUMERIC 或 DBTYPE_DECIMAL,相应的 NUMERIC_PRECISION 和 NUMERIC_SCALE 也必须是有效的非空值。

从可选的 INDEXES 架构行集中,通过按原先规则设置限制,SQL Server 可在指定的远程表上寻找索引。SQL Server 从找到的索引条目中检索 TABLE_CATALOG、TABLE_SCHEMA、TABLE_NAME、INDEX_CATALOG、INDEX_SCHEMA、INDEX_NAME、PRIMARY_KEY、UNIQUE、CLUSTERED、FILL_FACTOR、ORDINAL_POSITION、COLUMN_NAME、COLLATION、CARDINALITY 和 PAGES 列。

从可选的 TABLES_INFO 行集中,SQL Server 寻找有关指定远程表的附加信息(例如书签支持、书签类型和长度)。除了 TABLES_INFO 行集中的 DESCRIPTION 列以外,所有的列都被使用。TABLES_INFO 行集中的信息按如下要求使用:

  • BOOKMARK_DURABILITY 列用于实现更有效的键集游标。如果该列的值为 BMK_DURABILITY_INTRANSACTION 或更高持久性的值,SQL Server 在实现键集游标时,将对远程表行使用基于书签的检索和更新。

  • BOOKMARK_TYPE、BOOKMARK_DATA TYPE 和 BOOKMARK_MAXIMUM_LENGTH 列用于在编译查询时确定书签的元数据。如果这些列不被支持,SQL Server 将在编译时通过 IOpenRowset 打开基本表行集来获得书签信息。

如果不支持 IDBSchemaRowset 并且远程表名称包含了目录或架构名,则 SQL Server 将要求 IDBSchemaRowset 并返回一个错误。但是,如果既没有提供目录名,也没有提供架构名,SQL Server 将打开对应于远程表的行集,并从行集对象的强制接口 IColumnsInfo 中检索列元数据。

SQL Server 通过调用 IOpenRowset::OpenRowset 打开对应于表的行集。提供给 OPENROWSET 的表名是由目录、架构和对象名等部分构成的。

  • 名称的每个部分(目录、架构、对象名)都使用提供程序的引用符 (DBLITERAL_QUOTE) 引用,然后使用 DBLITERAL_CATALOG_SEPARATOR 字符和 DBLITERAL_SCHEMA_SEPARATOR 字符连接到一起。名称的构造遵循 IOpenRowset 中的 OLE DB 规则。

  • 在行集对象打开后,可通过 IColumnsInfo::GetColumnInfo 检索表中的列元数据。

如果 IDBSchemaRowset 不支持 TABLES、COLUMNS 和 TABLES_INFO 行集,SQL Server 将打开两次基本表上的行集:在查询编译时打开一次来检索元数据,在查询运行时再打开一次。由于打开行集而受影响的提供程序(例如,运行更改实时设备状态的代码,发送电子邮件,运行任意用户提供的代码)必须注意这种行为。

检索统计信息

如果提供程序支持基本表上的分布式统计,那么 SQL Server 2000 将使用这些统计。有两种统计可用于 SQL Server 查询处理器:

  • 列(或元组)基数:它是在一个表的列(或一组列)中唯一值的数目。可用于依据列评估谓词的选择性。支持分布式统计的提供程序必须支持至少一种基数。

  • 柱状图:如果值的分布不均匀,则唯一值的数目对于评估谓词的选择性是不够充分的。在此情况下,提供一个柱状图即可就表中列值的分布提供更好的图形化信息。

有了统计就能使 SQL Server 查询优化程序更好地评估一个查询中的中间操作的基数,这将使它生成更好的执行方案。

OLE DB 提供程序应支持以下分布式统计:

  • 强制:支持属性 (1) DBPROP_TABLESTATISTICS,该属性指示是否支持列或元组基数以及是否支持柱状图;和属性 (2) DBPROP_OPENROWSETSUPPORT,该属性使用 DBPROPVAL_ORS_HISTOGRAM 位来指示是否支持柱状图。

  • 强制:TABLE_STATISTICS 架构行集。TABLE_STATISTICS 架构行集列出了给定数据库中可用的统计。它也包含了架构行集本身的列或元组基数,同时指示了特定列是否支持柱状图。为了使 SQL Server 能够使用统计,此架构行集中的 TABLE_NAME、STATISTICS_NAME、STATISTICS_TYPE、COLUMN_NAME 和 ORDINAL_POSITION 列是强制的。COLUMN_CARDINALITY 或 TUPLE_CARDINALITY 中至少有一个是强制的。如果支持柱状图,则 NO_OF_RANGES 也是强制的。

  • 可选:可选地,如果提供程序支持柱状图,它应支持 IOpenRowset::OpenRowset 方法的增强功能(允许通过指定相应统计的 DBID 来打开一个柱状图行集)。

有关统计接口的完整信息,请参阅 OLE DB 2.6 规范。

约束

如果 OLE DB 提供程序支持 OLE DB 2.6 的新架构行集 CHECK_CONSTRAINTS_BY_TABLE,SQL Server 2000 查询优化程序也可以使用远程数据源中基本表上的 CHECK 约束。架构行集的 CHECK_CLAUSE 列将返回符合 SQL-92 语法的 CHECK 子句谓词。查询优化程序使用约束信息来消除或简化因表中约束的存在而总为真或总为假的谓词。

事务管理

SQL Server 通过使用提供程序的 ITransactionLocal(用于本地事务)和 ITransactionJoin(用于分布式事务)OLE DB 接口支持以事务方式访问分布式数据。通过启动提供程序的本地事务,SQL Server 可保证单元写操作。通过使用分布式事务,SQL Server 可确保包括多个节点的事务在所有节点中都有同样的结果(无论是提交还是终止)。如果提供程序不支持必要的 OLE DB 事务相关接口,根据本地事务的环境将不允许针对该提供程序进行更新操作。

下表(表 2)描述了在用户执行分布式查询(给定了提供程序的功能和本地事务的环境)时发生的事情。针对提供程序的读操作是指一条 SELECT 语句,或者指远程表用在 SELECT INTO、INSERT、UPDATE 或 DELETE 语句的输入端的情形。针对提供程序的写操作是指 INSERT、UPDATE 或 DELETE 语句,其中远程表作为目的表。

表 2:基于提供程序的功能和事务环境的分布式查询结果。

分布式查询
发生
提供程序不
支持
ITransactionLocal
提供程序同时支持
ItransactionLocal
但不支持
ITransactionJoin
提供程序同时支持

ItransactionLocal

ITransactionJoin
在自身事务中(非用户事务)。默认情况下,只允许读操作。如果启用提供程序级选项 Nontransacted Updates,则允许写操作。(当启用该选项时,SQL Server 不能保证提供程序数据的原子性和一致性。这将导致写操作的影响部分地反映到远程数据源中,而且无法撤消。)所有语句都允许在远程数据上运行。键集游标是只读的。
本地事务在提供程序上以当前 SQL Server 会话隔离级别启动,然后在语句运行成功后提交。(除非使用 SET TRANSACTION ISOLATION LEVEL 对 SQL Server 会话的隔离级别进行修改,否则默认级别是 READ COMMITTED。提供程序必须支持请求的隔离级别。)
允许所有语句。键集游标是只读的。
本地事务在提供程序上以当前 SQL Server 会话隔离级别启动,然后在语句运行成功后提交。
在用户事务中(也就是说,发生在 BEGIN TRAN 或 BEGIN DISTRIBUTED TRAN 和 COMMIT 之间)。如果事务的隔离级别是 READ COMMITTED(默认值)或更低,则允许读操作。

如果隔离级别更高,将不允许分布式查询。

只允许读操作。

新的分布式事务在提供程序上以当前 SQL Server 会话隔离级别启动。

允许所有语句。
新的分布式事务在提供程序上以当前 SQL Server 会话隔离级别启动,然后在用户事务提交时提交。对于修改数据的语句,默认情况下,SQL Server 将在分布式事务下启动一个嵌套的事务,这样出现某种错误时就可以停止修改数据语句,而不必停止周围的事务。如果 XACT_ABORT SET 选项为打开状态,SQL Server 就不需要嵌套事务支持,而且在修改数据的语句出错时可停止周围的事务。

分布式查询中数据类型的处理

OLE DB 提供程序按照由 OLE DB 定义的数据类型(由 OLE DB 的 DBTYPE 指示)表明它们的数据。SQL Server 在服务器中以本地的 SQL Server 类型处理外部数据;不管数据是被 SQL Server 使用还是从 SQL Server 导出,这种处理方式都会产生从 OLE DB 数据类型到 SQL Server 本地数据类型的映射(见表 3)或者从 SQL Server 本地数据类型到 OLE DB 数据类型的映射。这种映射是以隐含方式实现的,除非另外注明。

分布式查询中的数据类型使用下列两种映射方式之一进行处理:

  • 使用端映射,当远程表出现在 SELECT 语句中并位于 INSERT、UPDATE 和 DELETE 语句的输入端时,该映射在使用端将类型从 OLE DB 数据类型映射为 SQL Server 本地数据类型。

  • 导出端映射,当远程表作为 INSERT 或 UPDATE 语句的目的表出现时,该映射在导出端将类型从 SQL Server 数据类型映射为 OLE DB 数据类型。

表 3:SQL Server 和 OLE-DB 数据类型映射表。

OLE DB 类型DBCOLUMNFLAGSQL Server 数据类型
DBTYPE_I1* numeric(3,0)
DBTYPE_I2 smallint
DBTYPE_I4 int
DBTYPE_I8 numeric(19,0)
DBTYPE_UI1 tinyint
DBTYPE_UI2* numeric(5,0)
DBTYPE_UI4* numeric(10,0)
DBTYPE_UI8* numeric(20,0)
DBTYPE_R4 float
DBTYPE_R8 real
DBTYPE_NUMERIC numeric
DBTYPE_DECIMAL decimal
DBTYPE_CY money
DBTYPE_BSTRDBCOLUMNFLAGS_ISFIXEDLENGTH=true
或最大长度大于 4000 个字符
ntext
DBTYPE_BSTRDBCOLUMNFLAGS_ISFIXEDLENGTH=truenchar
DBTYPE_BSTRDBCOLUMNFLAGS_ISFIXEDLENGTH=falsenvarchar
DBTYPE_IDISPATCH Error
DBTYPE_ERROR Error
DBTYPE_BOOL bit
DBTYPE_VARIANT* nvarchar
DBTYPE_IUNKNOWN Error
DBTYPE_GUID uniqueidentifier
DBTYPE_BYTESDBCOLUMNFLAGS_ISLONG=true 或最大长度大于 8000image
DBTYPE_BYTESDBCOLUMNFLAGS_ISROWVER=true,
DBCOLUMNFLAGS_ISFIXEDLENGTH=true、
列大小等于 8 或未报告最大长度。
timestamp
DBTYPE_BYTESDBCOLUMNFLAGS_ISFIXEDLENGTH=truebinary
DBTYPE_BYTESDBCOLUMNFLAGS_ISFIXEDLENGTH=truevarbinary
DBTYPE_STRDBCOLUMNFLAGS_ISFIXEDLENGTH=truechar
DBTYPE_STRDBCOLUMNFLAGS_ISFIXEDLENGTH=truevarchar
DBTYPE_STRDBCOLUMNFLAGS_ISLONG=true 或最大长度大于 8000 个字符或未报告最大长度。text
DBTYPE_WSTRDBCOLUMNFLAGS_ISFIXEDLENGTH=truenchar
DBTYPE_WSTRDBCOLUMNFLAGS_ISFIXEDLENGTH=falsenvarchar
DBTYPE_WSTRDBCOLUMNFLAGS_ISLONG=true 或 最大长度大于 4000 个字符或未报告最大长度。ntext
DBTYPE_UDT Error
DBTYPE_DATE* datetime
DBTYPE_DBDATE datetime(必须显式转换)
DBTYPE_DBTIME datetime(必须显式转换)
DBTYPE_DBTIMESTAMP* datetime
DBTYPE_ARRAY Error
DBTYPE_BYREF Ignored
DBTYPE_VECTOR Error
DBTYPE_RESERVED Error

* 表示如果 SQL Server 中没有确切的等价数据类型,则转换为某种形式的 SQL Server 类型。这种转换将导致精确度降低、上溢或下溢。如果 SQL Server 的未来版本支持相应的数据类型,则默认的隐式映射可能会改变。

注意: numeric(p,s) 表示 SQL Server 的数据类型 numeric 精度为 p,刻度为 s 。对于 DBTYPE_NUMERIC 和 DBTYPE_DECIMAL,允许使用的最大精度为 38。创建访问器时,提供程序必须支持以 DBTYPE_WSTR 绑定到 DBTYPE_BSTR 列。DBTYPE_VARIANT 列当作 Unicode 字符串 nvarchar 使用。这需要提供程序支持从 DBTYPE_VARIANT 向 DBTYPE_WSTR 的转换。提供程序应按照 OLE DB 的定义实现该转换。有关详细信息,请参阅附录 A:SQL Server 采用的 OLE DB 接口

解释数据类型映射

是否映射对 SQL Server 类型由 OLE DB 数据类型和描述该列或数量值的 DBCOLUMNFLAGS 值共同确定。在使用 COLUMNS 架构行集时,由 DATA_TYPE 和 COLUMN_FLAGS 列来代表这些值。在使用 IColumnsInfo::GetColumnInfo 接口时,由 DBCOLUMNINFO 结构的 wType 和 dwFlags 成员代表这些信息。

若要在包括特定的 DBTYPE 和 DBCOLUMNFLAG 值的给定列上用使用端映射,应在该表中寻找相应的 SQL Server 类型。在表达式中远程表的列的类型规则可以通过如下的简单规则描述:

给定远程列的值在 Transact-SQL 表达式中是合法的条件为,它在上表中所映射的 SQL Server 类型在相同的上下文中是合法的。

表和规则定义:

  • 比较和表达式。

    通常,如果 <op> 是可用于 X 数据类型和 <远程列> 所映射数据类型上的有效运算符,则 X <op> <远程列> 就是一个有效表达式。

  • 显式转换。

    允许 Convert (X, <远程列>) 的条件:<远程列> 的 DBTYPE 映射为本地数据类型 Y(如上表所示)而且允许从 Y 到 X 的显式转换。

如果用户要将远程数据转换为非默认本地数据类型,则必须使用显示转换。

若要在对远程表使用 UPDATE 和 INSERT 语句时使用导出端映射,应使用同样的表将本地的 SQL Server 数据类型映射为 OLE DB 数据类型。如果下述情况之一存在,则允许将 SQL Server 类型 (S1) 映射为给定的 OLE DB 类型 (T):

  • 相应的映射可以在映射表(表 3)中直接找到。

  • 允许 S1 隐式转换为另一种 SQL Server 类型 S2,而 S2 对类型 T 的映射包含在映射表(表 3)中。

大对象 (LOB) 的处理

如映射表(表 3)中所述,如果 DBTYPE_STR、DBTYPE_WSTR 或 DBTYPE_BSTR 类型的列也报告 DBCOLUMNFLAGS_ISLONG,或者它们的最大长度超过 4,000 个字符(或未报告最大长度),SQL Server 将相应把它们处理为 text 或 ntext 列。类似地,对于 DBTYPE_BYTES 列,如果设置了 DBCOLUMNFLAGS_ISLONG,或最大长度大于 8,000 个字节(或未报告最大长度),该列将被视为 image 列。Text、ntext 和 image 列称为 LOB 列。

SQL Server 不会在 OLE DB 提供程序的 LOB 上列出完整的文本或图像功能。在 OLE DB 提供程序的大对象上不支持 TEXTPTRS 的;因此,也不支持相关的功能,例如,TEXTPTR 系统函数以及 READTEXT、WRITETEXT 和 UPDATETEXT 语句。支持检索整个 LOB 列的 SELECT 语句,也支持对远程表上整个大对象列的 UPDATE 和 INSERT 语句。

如果提供程序支持 LOB 列上的结构化存储接口,SQL Server 将使用它们。结构化存储接口如下所示(按优先权和功能的递增顺序排列):ISequentialStream、Istream 和 ILockBytes。如果提供程序支持这些接口中的一个或多个,当通过 IDBProperties 接口查询提供程序时,它必须将 DBPROPVAL_OO_BLOB 作为 DBPROP_OLEOBJECTS 属性的值返回。同样,提供程序应在 DBPROP_STRUCTUREDSTORAGE 属性中指出它所支持的接口。

如果提供程序不支持 LOB 列上的任何结构化存储接口,SQL Server 2000 将在自身实现该接口,同时仍将它们按 text、ntext 或 image 列列出。

访问 LOB 列

如果提供程序支持结构化存储接口之一,SQL Server 在查询运行时按如下步骤检索 LOB 列:

  1. 在通过 IOpenRowset::OpenRowset 打开行集合前,SQL Server 请求对大对象列上的一个或多个结构化存储接口(ISequentialStream、Istream 和 ILockBytes)的支持。提供程序支持的第一个接口是必需的;而其他接口则是可选的,可通过将 DBPROP 结构的 dwOptions 元素设置为 DBPROPOPTIONS_SETIFCHEAP 来请求它们。例如,如果提供程序同时支持 ISequentialStream 和 ILockBytes ,则 ISequentialStream 是必需的,而 ILockBytes 则是可选的。

  2. 打开行集后,SQL Server 使用 IRowsetInfo::GetProperties 来识别行集中可用的实际接口。提供程序返回的最后一个或最优先接口将被使用。当 SQL Server 创建基于大对象列的访问器时,该列绑定为 DBTYPE_IUNKNOWN,绑定中 DBOBJECT 结构的 iid 元素设置为接口。

读取 LOB 列

使用被请求的结构化存储接口的接口指针(在 IRowset::GetData 生成的行缓冲区中返回)来读取大对象列。如果提供程序不支持同时打开多个 LOB(即不支持 DBPROP_MULTIPLE_STORAGEOBJECTS)并且该行有多个大对象列时,SQL Server 将把 LOB 复制到本地工作表中。

在 LOB 列上的 UPDATE 和 INSERT 语句

SQL Server 通过向提供程序传递一个指向新的存储对象的指针来修改存储对象,而不使用提供程序所提供的接口。对于每个 LOB 列,存储对象上被更新或插入的值是使用选定的结构化存储接口创建的。根据操作是 UPDATE 还是 INSERT,指向存储对象的指针分别通过 IRowsetChange::SetData 或 IRowsetChange::InsertRow 传递到提供程序。

错误处理

如果对 OLE DB 提供程序特定方法的调用返回错误代码,SQL Server 将查找提供程序的扩展错误信息,然后将有关错误条件的信息返回给用户。

SQL Server 使用由 OLE DB 指定的 OLE DB 错误对象。其中的高级步骤有:

  1. 如果方法调用返回来自提供程序的错误代码,SQL Server 将查找 ISupportErrorInfo 接口。如果支持该接口,SQL Server 将调用 ISupportErrorInfo::InterfaceSupportsErrorInfo 来验证生成错误代码的接口是否支持该错误对象。

  2. 如果接口支持该错误对象,SQL Server 将调用 GetErrorInfo 函数来获得一个指向当前错误对象的 IErrorInfo 接口指针。

  3. SQL Server 使用 IErrorInfo 接口获得指向 IErrorRecords 接口的指针。

  4. SQL Server 使用 IErrorRecords 来循环查找对象中的所有错误记录并获得对应于每个记录的错误信息文本。

有关如何使用提供程序的错误对象的详细信息,请参阅 OLE DB 文档。

安全性

当使用者连接到 OLE DB 提供程序时,通常情况下,除非使用者希望作为集成安全用户被验证,否则提供程序将需要用户 ID 和密码。在分布式查询中,SQL Server 将作为 OLE DB 提供程序的使用者(代表执行分布式查询的 SQL Server 登录)。SQL Server 将当前的 SQL Server 登录映射为链接服务器上的用户 ID 和密码。

这些映射可以被用户指定用于给定的链接服务器,并可以通过系统存储过程 sp_addlinkedsrvlogin 和 sp_droplinkedsrvlogin 来建立并管理。通过使用 IDBProperties::SetProperties 来建立初始化组属性 DBPROP_AUTH_USERID 和 DBPROP_AUTH_PASSWORD,由映射确定的用户 ID 和密码可在连接建立的过程中传递到提供程序。

当客户端通过 Microsoft® Windows NT® 的身份验证连接到 SQL Server 时,如果登录使用 sp_addlinkedsrvlogin 建立自身的映射,那么 SQL Server 在连接建立的过程中将尝试模拟客户端的安全上下文并设置提供程序的 DBPROP_AUTH_INTEGRATED 属性。此过程称为“委派”。只有 Windows® 2000 完全支持委派。在 Windows NT 4.0 或更早版本中,只有提供程序完全位于 SQL Server 机器中并且没有通过网络连接到后端数据源时才支持委派。在这种情况下,Windows NT 已验证的登录必须映射为特定的用户 ID 和密码才能访问链接服务器。

在确定了用于连接的安全上下文后,OLE DB 提供程序将全面负责安全上下文的验证以及对数据源中数据对象的权限检查。

有关 sp_addlinkedsrvlogin 和 sp_droplinkedsrvlogin 的详细信息,请参阅 SQL Server Books Online。

查询执行方案

执行分布式查询时,SQL Server 与 OLE DB 提供程序进行交互有下述一个或多个方案:

  • 远程查询

  • 索引访问

  • 单纯表扫描

  • UPDATE 和 DELETE 语句

  • INSERT 语句

  • 传递查询

远程查询

SQL Server 生成一个 SQL 查询,它将计算出由提供程序完整执行的初始查询的一部分。该方案只能用于 SQL 命令提供程序。SQL Server 通过生成 SQL 查询将操作转给提供程序的程度取决于提供程序支持的 SQL 语法。提供程序应通过如下方式指出它的 SQL 支持级别:

  1. 通过 DBPROP_SQLSUPPORT 属性指出 SQL Minimum、ODBC Core 或 SQL-92 Entry 级别。SQL Minimum 语法级别是 SQL Server 2000 支持的新级别,它允许 SQL Server 向支持 SQL 简单子集的简单提供程序发送远程查询。该级别包含基本 SELECT 语句,即不包括子查询、在 FROM 子句中使用多表(因此无联接)和 GROUP BY 的 SELECT 语句。有关 SQL Server 用来为各语法级别的提供程序生成远程查询的 SQL 语法的子集的详细信息,请参阅附录 B:用于生成远程查询的 SQL 子集

  2. 通过支持各种 SQL Server 特有的属性来指出对个别 SQL 功能的支持,这些 SQL 功能没有包括在 DBPROP_SQLSUPPORT 报告的语法级别中。在本节后面描述了属性列表和 SQL Server 使用它们的方法。

SQL Server 在 Transact-SQL 字符串中使用问号 (?) 作为参数标记的带参数查询命令。带参数查询命令可以用于 SQL Server、Microsoft Jet 和 Oracle OLE DB 提供程序。对于其他提供程序,如果该提供程序支持 Command 对象的 ICommandWithParameters 属性,并且至少满足如下条件之一,则也可以使用带参数查询命令:

  • 提供程序通过 DBPROP_SQLSUPPORT 属性指出支持 SQL Server 的 ODBC Core 级别。

  • 通过使用 IDBPProperties 支持 SQL Server 特有的属性 SQLPROP_DYNCMICSQL,提供程序指出对问号 (?) 参数标记的支持。有关详细信息,请参阅下一节“提供程序属性”。

  • 系统管理员通过设置提供程序上的选项 Dynamic Parameters 来使 SQL Server 生成带参数查询。

当 SQL Server 生成在远程执行的 SQL 文本时,表名和列名被提供程序的引用字符(IDBInfo 接口的 DBLITERAL_QUOTE 文字)引起来。如果不支持该文字,则表名和列名不会被引起来。

如果提供程序支持带参数查询执行,SQL Server 将带参数查询执行策略视为执行一个远程表和本地表的联接。带参数查询根据由本地表中每一行生成的参数值重复执行。这种策略减少了从提供程序获取的行数,并且有利于行数较少的本地表联接到行数较多的远程表。远程联接策略可以使用 REMOTE 联接优化提示来强制执行。有关带参数查询执行的详细信息,请参阅 SQL Server Books Online。

下面是在远程查询方案中针对提供程序所进行的高级步骤:

  1. SQL Server 使用 IDBCreateCommand::CreateCommand 从 Session 对象创建 Command 对象。

  2. 如果将服务器配置选项 Remote Query Timeout 的值设置为大于零,SQL Server 将使用 ICommandProperties::SetProperties 把 Command 对象的 DBPROP_COMMANDTIMEOUT 设置为同样的值;必须调用 ICommand::SetCommandText 来将命令文本设置为已生成的 Transact-SQL 字符串。

  3. SQL Server 调用 ICommandPrepare::Prepare 来准备命令。如果提供程序不支持该接口,SQL Server 将继续第 4 步。

  4. 如果生成的查询是带参数的,SQL Server 使用 ICommandWithParameters::SetParameterInfo 来描述这些参数并使用 IAccessor::CreateAccessor 创建使用这些参数的访问器。

  5. SQL Server 调用 ICommand::Execute 来执行命令并创建行集。

  6. SQL Server 使用 IRowset 接口浏览并使用表中的行。使用 IRowset::GetNextRows 获取行,使用 IRowset::RestartPosition 来重定位行集的起始点,使用 IRowset::ReleaseRows 释放行。

用于远程查询执行的提供程序属性

如果提供程序支持的 SQL 功能没有包含在 DBPROP_SQLSUPPORT 报告的语法级别中,可以通过使用各种提供程序特有的属性来指出它们。

  • SQLPROP_GROUPBY。该属性对支持 SQL-Minimum 级别的提供程序比较有意义。它指出提供程序在 SELECT 语句中支持 GROUP BY 和 HAVING 子句。另外,它还指出提供程序支持如下五种聚合函数:MIN、MAX、SUM、COUNT 和 AVG。提供程序可能不支持在这些合计函数参数中使用 DISTINCT。

  • SQLPROP_SUBQUERIES。该属性对支持 SQL-Minimum 级别的提供程序比较有意义。它指出该提供程序支持 SQL-92 entry 级别所规定的子查询。包括 SELECT 列表中的子查询,以及 WHERE 子句中的关系子查询,IN、EXISTS、ALL 和 ANY 运算符。

  • SQLPROP_DATELITERALS。该属性对任何提供程序(包括支持 SQL-92 entry 级别的提供程序)都比较有意义。对日期时间文字的标准语法的支持不属于 SQL-92 entry 级别。该 SQL Server 特有的属性指出提供程序支持 SQL-92 标准所规定的日期时间文字语法。

  • SQLPROP_ANSILIKE。该属性对支持 SQL-Minimum 级别的提供程序比较有意义。它指出提供程序支持每个 SQL-92 entry 级别所规定的 LIKE 运算符(使用 '%' 和 '_' 作为通配符)。由于 SQL-Minimum 级别没有包括对 LIKE 的支持,所以它对支持 SQL-Minimum 级别的提供程序非常有用。

  • SQLPROP_INNERJOIN。该属性对支持 SQL-Minimum 级别的提供程序比较有意义。它指出支持在 FROM 子句中使用多个表。由于 SQL-Minimum 级别不支持联接,所以它对只支持 SQL-Minimum 级别的提供程序非常有用。但是,这并非指出了对显式 JOIN 关键字和 OUT 联接的支持。它只指出了支持在 FROM 子句使用多个表的隐含联接。

  • SQLPROP_DYNAMICSQL。该属性指出支持使用 '?' 作为参数标记。应支持参数标记在 WHERE 子句或 SELECT 列表中替代一个数量项目。对 '?' 运算符标记的支持允许 SQL Server 向提供程序发送带参数查询。

  • SQLPROP_NESTEDQUERIES。该属性指出支持在 FROM 子句中嵌套 SELECT(例如,SELECT * FROM (SELECT * FROM T))。在多种情况下,SQL Server 在生成远程执行的查询字符串时,在查询的 FROM 子句中使用嵌套的 SELECT 语句。由于对嵌套 SELECT 的支持并不是 SQL-92 entry 级别所必需的,除非提供程序也设置了本属性,否则 SQL Server 不会向提供程序委派带有嵌套 SELECT 语句的查询。另外,系统管理员也可以设置提供程序的 Nested Queries 选项,以使 SQL Server 生成用于提供程序上的嵌套查询。

提供程序能够通过使用名为 SQLPROPSET_OPTHINTS 的 SQL Server 特殊属性集来支持这些属性,并获得已定义的 PROPID 值。属性集 SQLPROPSET_OPTHINTS 和这两个属性通过使用以下常数来定义:

extern const GUID SQLPROPSET_OPTHINTS = { 0x2344480c, 0x33a7, 0x11d1,    { 0x9b, 0x1a, 0x0, 0x60, 0x8, 0x26, 0x8b, 0x9e } };enum SQLPROPERTIES {SQLPROP_NESTEDQUERIES = 0x4,         SQLPROP_DYNAMICSQL = 0x5,         SQLPROP_GROUPBY = 0x6,         SQLPROP_DATELITERALS = 0x7,         SQLPROP_ANSILIKE = 0x8,         SQLPROP_INNERJOIN = 0x9,         SQLPROP_SUBQUERIES = 0x10   };

隐含的字符集和排序顺序

SQL Server 2000 支持在列级别上指定字符数据的排序。排序包括非 Unicode 字符数据(char 和 varchar 列)的字符集和排序顺序规范。对于 Unicode 数据(nchar 和 nvarchar 列),排序只指定了排序顺序。

只有在链接服务器使用的字符集(非 Unicode 数据)、排序顺序、字符串比较语法和本地服务器一致时,SQL Server 2000 才将字符串比较操作委派给提供程序。

在链接服务器是 SQL Server 时,SQL Server 自动确定排序的兼容性。对于其他提供程序,系统管理员必须为 SQL Server 指出给定的链接服务器上的字符数据的排序方式。在 SQL Server 2000 中,支持名为 Collation Name 的新的链接服务器选项。如果系统管理员确定链接服务器上采用的排序语法和 SQL Server 标准语法一致,就能将 Collation Name 选项设置为排序名。Collation Name 选项能够使用系统存储过程 sp_serveroption 来设置。只有满足了如下两个条件时才应该设置该选项:

  • 远程排序顺序和字符集与指定的 SQL Server 排序一致。

  • OLE DB 提供程序使用的字符串比较的语法符合 SQL-92 标准规范或等同于 SQL Server 的比较语法。

为了向下兼容,仍支持 SQL Server 7.0 中的 Collation Compatible 选项。将其设置为 true 等于将 Collation Name 选项设置为 SQL Server 主数据库的默认排序方式。新的应用程序应使用 Collation Name 选项,而不是 Collation Compatible 选项。

索引访问

SQL Server 使用提供程序列出的索引来执行分布式查询的某些谓词。该方案只能在用户设置提供程序选项 Index as Access Path 时才能用于索引提供程序。下面是在使用索引执行查询时 SQL Server 在提供程序上运行的主要高级步骤:

  1. 通过使用完整的表名和索引名调用 IOpenRowset::OpenRowset 来打开索引行集。完整表名和索引名依据前面的远程查询方案中所述的方式生成。

  2. 通过使用完整表名调用 IOpenRowset::OpenRowset 来打开基本表行集。

  3. 通过调用 IRowsetIndex::SetRange 根据查询谓词设置索引行集的范围。

  4. 通过索引行集上的 IRowset 扫描索引行集的行。

  5. 使用检索到的索引行中的书签列来通过 IRowsetLocate::GetRowsByBookmark 从基本表行集中获取相应的行。

在基本表上打开行集时,行集属性 DBPROP_IRowsetLocate 和 DBPROP_BOOKMARKS 是必需的。

单纯表扫描

SQL Server 扫描提供程序的整个远程表并在本地运行所有的查询命令。通过调用 IOpenRowset::OpenRowset 打开表中相应的行集。SQL Server 使用目录、架构和对象名部分按以下方式来构造提供给 OPENROWSET 的表名:

  1. 每一个名称段都使用提供程序的引用字符 (DBLITERAL_QUOTE) 引用,然后使用 DBLITERAL_CATALOG_SEPARATOR 字符连接它们。

  2. 行集对象打开后,SQL Server 使用 IColumnsInfo 接口来验证该表运行时元数据是否和编译时的元数据一致。

  3. SQL Server 使用 IRowset 接口浏览并使用表中的行。使用 IRowset::GetNextRows 获取行,使用 IRowset::RestartPosition 来重定位行集的起始点,使用 IRowset::ReleaseRows 释放行。

UPDATE 和 DELETE 语句

要从 SQL Server 分布式查询中对远程表进行更新和删除,必须满足如下条件:

  • 提供程序必须支持在被更新或删除的表上使用 IOpenRowset 打开的行集的书签。

  • 提供程序必须支持在被更新或删除的表上使用 IOpenRowset 打开的行集合上的 IRowsetLocate 和 IRowsetChange 接口。

  • IRowsetChange 接口必须支持更新 (SetData) 和删除 (DeleteRows) 方法。

  • 如果提供程序不支持 ITransactionLocal,则仅在该提供程序设置了 Non-transacted 选项且语句不在用户事务中时,才允许使用 UPDATE/DELETE 语句。

  • 如果提供程序不支持 ITransactionJoin,只有不在用户事务中时才允许 UPDATE/DELETE 语句。

下列行集属性是在被更新的表中打开的行集所必需的:DBPROP_IRowsetLocate、DBPROP_IRowsetChange 和 DBPROP_BOOKMARKS。将DBPROP_UPDATABILITY 行集属性设置为 DBPROPVAL_UP_CHANGE 还是 DBPROPVAL_UP_DELETE 取决于执行的操作是 UPDATE 还是 DELETE。

以下是在提供程序上运行 UPDATE 或 DELETE 操作的高级步骤:

  1. SQL Server 通过 IOpenRowset 接口打开基本表行集。SQL Server 需要行集上的上述属性。

  2. SQL Server 确定符合条件的将被更新或删除的行。

  3. SQL Server 通过 IRowsetLocate 接口使用书签在符合条件的行中进行定位。

  4. 使用 IRowsetChange::SetData(用于 UPDATE 操作)或 IRowsetChange::DeleteRows(用于 DELETE 操作)在符合条件的行上作出所需的更改。

INSERT 语句

支持远程表上的 INSERT 语句的条件要比 UPDATE 和 DELETE 语句宽松:

  • 提供程序必须支持在目的基本表中的行集上的 IRowsetChange::InsertRow 操作。

  • 如果提供程序不支持 ITransactionLocal,则仅在链接服务器设置了 Non-transacted updates 选项且语句不在用户事务中时,才允许使用 INSERT 语句。

  • 如果提供程序不支持 ITransactionJoin,只有不在用户事务中时才允许 INSERT 语句。

SQL Server 使用 IOpenRowset::OpenRowset 打开基本表的行集并调用 IRowsetChange::InsertRow 将新的行插入基本行集中。

传递查询

除了赋予 ICommand 的命令文本是用户提交的(不由 SQL Server 解释)命令字符串外,本方案和“远程查询”方案类似。SQL Server 在调用 ICommandText::SetCommandText 时使用 DBGUID_DEFAULT 作为文字标识符。DBGUID_DEFAULT 指出提供程序应使用它的默认语法。如果该命令文本返回多个结果集(例如,如果该命令调用一个返回多个结果集的存储过程),SQL Server 将只使用命令返回的第一个结果集。

有关 SQL Server 使用的所有 OLE DB 接口的列表,请参阅附录 A:SQL Server 采用的 OLE DB 接口

总结

Microsoft SQL Server 2000 为访问异类数据源中的数据提供了最可靠的一套工具。通过了解 SQL Server 提供的 OLE-DB 接口,开发人员能够更好地控制和完善分布式查询。

附录 A:SQL Server 采用的 OLE DB 接口

下表(表 4)列出了 SQL Server 使用的全部 OLE DB 接口。“必要”列说明该接口是 SQL Server 所需的 OLE DB 功能中最基本的部分,还是可选的。如果一个给定的接口未标记为必要,SQL Server 仍然能够访问提供程序,但是某些特殊的 SQL Server 功能或优化功能不能用于该提供程序。

对于可选接口,“方案”列指定了使用该接口的方案(是六个方案中的一个或多个)。例如,基本表行集上的 IRowsetChange 接口是可选接口;该接口用于 UPDATE 和 DELETE 语句方案以及 INSERT 语句方案中。如果该接口不被支持,则对提供程序的 UPDATE、DELETE 和 INSERT 语句也不能被支持。其他一些可选接口的“方案”列中标记为“性能”,表示该接口能够提高性能。例如,如果不支持 IDBSchemaRowset 接口,SQL Server 必须打开行集两次:一次获得元数据,另一次执行查询。通过支持 IDBSchemaRowset,将提高 SQL Server 的性能。

表 4:SQL Server 采用的接口

对象接口必要注释方案
Data Source 对象IDBInitialize初始化并设置数据和安全上下文。 
 IDBCreateSession创建 DB 会话对象。 
 IDBProperties获得有关提供程序功能的信息,设置初始化属性,必要属性:DBPROP_INIT_TIMEOUT。 
 IDBInfo获得引用文字、目录、名称、部分、分隔符、字符等等。远程查询。
DB Session 对象IDBSchemaRowset获得表/列的元数据。
需要的行集:
TABLES、COLUMNS、PROVIDER_TYPES;
其他可能用到的行集:INDEXES、TABLE_STATISTICS。
性能,索引访问。
 IOpenRowset打开表、索引和柱状图上的行集。 
 IGetDataSource用于从 DB 会话对象返回到 DSO。 
 IDBCreateCommand用于为支持查询的提供程序创建命令对象(查询)。远程查询,传递查询。
 ITransactionLocal用于事务方式的更新。UPDATE、DELETE 和 INSERT 语句。
 ITransactionJoin用于分布式事务支持。如果在用户事务中,则必需有 UPDATE、DELETE 和 INSERT 语句。
Rowset 对象IRowset扫描行。 
 IAccessor绑定到行集中的列。 
 IColumnsInfo获得行集中的列信息。 
 IRowsetInfo获得行集属性的信息。 
 IRowsetLocateUPDATE/DELETE 操作和基于索引的查找所需;用于使用书签来查找行。索引访问,UPDATE 和 DELETE 语句。
 IRowsetChange对行集进行 INSERTS/UPDATES/
DELETES 操作所需的。基于基本表的行集应支持该接口的 INSERT、UPDATE 和
DELETE 语句。
UPDATE、DELETE 和 INSERT 语句。
 IConvertType用于验证该行集是否支持它的列上的数据类型转换。 
IndexIRowset扫描行。索引访问,性能。
 IAccessor绑定到行集中的列。索引访问,性能。
 IColumnsInfo获得行集中的列信息。索引访问,性能。
 IRowsetInfo获得行集属性的信息。索引访问,性能。
 IRowsetIndex只用于索引上的行集合;用于索引功能(设置范围、搜索)。索引访问,性能。
CommandICommand 远程查询,传递查询。
 ICommandText用于定义查询文本。远程查询,传递查询。
 IColumnsInfo用于获得查询结果需要的列元数据。远程查询,传递查询。
 ICommandProperties用于指定根据命令返回的行集合上所需的属性。远程查询,传递查询。
 ICommandWithParameters用于带参数查询命令。远程查询,性能。
 ICommandPrepare用于准备获取元数据的命令(如果可用,用于传递查询中)。远程查询,性能。
Error 对象IErrorRecords用于获得指向 IErrorInfo 接口的对应于个别错误记录的指针。 
 IErrorInfo用于获得指向 IErrorInfo 接口的对应于个别错误记录的指针。 
任意对象ISupportErrorInfo用于验证给定的接口是否支持错误对象。 

注意:   Index 对象、Command 对象和 Error 对象不是强制的。如果它们被支持,则在“必要”列中指定的接口是强制的。

附录 B: 用于生成远程查询的 SQL 子集

SQL Server 查询处理器根据 SQL 命令提供程序生成的 SQL 子集取决于提供程序依据 DBPROP_SQLSUPPORT 属性所支持的语法级别。

支持 SQL Entry 级别和 ODBC Core 的 SQL 命令提供程序

SQL Server 将下面的 SQL 语言的子集用于由 SQL 命令提供程序执行的查询,这些 SQL 命令提供程序必须支持 SQL-92 Entry 级别或 ODBC Core :

  1. 包含 SELECT、FROM、WHERE、GROUP BY、UNION、UNION ALL、ORDER BY DESC、ASC 和 HAVING 子句的 SELECT 语句。

  2. UNION 和 UNION ALL 只能在支持 SQL-92 Entry 级别的提供程序上生成,不能在支持 ODBC Core 的提供程序上生成。

  3. SELECT 子句:
    • 在 SELECT 列表中的分级子查询。

    • 不带 AS 关键字的列别名。
  4. FROM 子句:
    • 没有使用显式 JOIN 关键字;使用逗号分隔的表名指定内部联接,在远程查询中没有指定外部联接。

    • 嵌套查询的格式:FROM ( <嵌套查询> ) <别名>。

    • 不带 AS 关键字的表别名。
  5. WHERE 子句使用带有 [NOT] EXISTS、ANY 和 ALL 的子查询。

  6. 表达式:
    • 聚合函数:MIN([DISTINCT])、MAX([DISTINCT])、COUNT([DISTINCT])、SUM([DISTINCT])、AVG([DISTINCT]) 和 COUNT(*)。

    • 比较运算符:<、=、<=、>、<>、>=、IS NULL 和 IS NOT NULL。

    • 布尔运算符:AND、OR 和 NOT。

    • 数学运算符:+、-、* 和 /。
  7. 常数:
    • 数字和货币常数总是由 () 括住。

    • 字符常数使用 '' 引住。

支持 SQL Minimum 级别的 SQL 命令提供程序

对于支持 SQL Minimum 级别的 SQL 命令提供程序,SQL Server 生成如下语法的 SQL。

此处的语法来自 ODBC 3.0 中描述的 SQL Minimum 语法。所有与该语法的不同之处都被突出显示。以粗斜体显示的项目就是添加到 ODBC 3.0 所述的 SQL Minimum 语法中的项目。以绿色删去的项目是从该语法中删除的项目。

select-statement ::=SELECT [ALL  DISTINCT] select-listFROM table-reference-list[WHERE search-condition][order-by-clause]SELECT clauseselect-list ::=      *  select-sublist [, select-sublist]...  select-sublist ::=       expression [alias]alias ::=         user-defined-nameFROM clausetable-reference-list ::=     table-reference table-identifier ::=     user-defined-name table-name ::=       table-identifier table-reference ::=    table-name WHERE clausesearch-condition ::=    boolean-term [OR search-condition] boolean-term ::=       boolean-factor [AND boolean-term] boolean-factor ::=    [NOT] boolean-primary boolean-primary ::=    comparison-predicate  ( search-condition ) comparison-predicate ::=   expression   comparison-operator   expression        expression IS [NOT] NULLcomparison-operator ::=    <  >  <=  >=  =  <> ORDER BY clauseorder-by-clause ::=     ORDER BY sort-specification [, sort-specification]...sort-specification ::=    {  column-name } [ASC  DESC] Common syntactic elementsexpression ::=       term  expression {+–} term term ::=          factor  term {*/} factorfactor ::=       [+–] primary primary ::=       column-name literal ( expression ) column-name ::=       [table-name.]column-identifier literal ::=       character-string-literal       integer-literal          exact-numeric-literalcharacter-string-literal ::=   '{character}? (字符指驱动程序或数据源的字符集中的任意字符。要在字符串中包括引号字符 ('),请使用两个引号字符 ('')。)integer-literal ::=      [+  -] unsigned-integerexact-numeric-literal::=   [+  -] unsigned-integer  [period unsigned-integer]        period unsigned-integerbase-table-name ::=    base-table-identifier base-table-identifier ::=    user-defined-name column-identifier ::=   user-defined-name user-defined-name ::=    letter[digit  letter  _]...unsigned-integer ::=    {digit}?digit ::=          0  1  2  3  4  5  6  7  8  9  period ::=      .

Tags:

作者:佚名
分享到: 微信 更多