管理 ntext、text 和 image 数据

重要说明重要提示

后续版本的 Microsoft SQL Server 将删除该功能。请避免在新的开发工作中使用该功能,并着手修改当前还在使用该功能的应用程序。请改用 varchar(max)、nvarchar(max) 和 varbinary(max) 数据类型。有关详细信息,请参阅使用大值数据类型

SQL Server ntext、text 和 image 数据类型能够在单个值中保存非常大的数据量(最大可达 2 GB)。单个数据值通常会很大,以至于应用程序无法在一个步骤中检索;某些值可能会大于客户端的可用虚拟内存。因此,要检索这些值通常需要一些特殊的步骤。

如果 ntext、text 和 image 数据值不超过 Unicode 串、字符串或二进制串的长度(分别为 4000 个字符、8000 个字符和 8000 个字节),就可以在 SELECT、UPDATE 和 INSERT 语句中引用它们,引用方式与较小的数据类型大致相同。例如,可以在 SELECT 语句的选择列表中引用包含短值的 ntext 列,引用方式与引用 nvarchar 列的方式相同。引用时必须遵守一些限制,例如不能在 WHERE 子句中直接引用 ntext、text 或 image 列。这些列可以作为返回其他数据类型(例如 ISNULL、SUBSTRING 或 PATINDEX)的函数的参数包含在 WHERE 子句中,也可以包含在 IS NULL、IS NOT NULL 或 LIKE 表达式中。

处理较大的数据值

如果 ntext、text 和 image 数据值较大,则必须逐块处理它们。Transact-SQL 和数据库 API 都包含使应用程序能够逐块处理 ntext、text 和 image 数据的函数。

数据库 API 按照通用的模式来处理长 ntext、text 和 image 列:

  • 若要读取一个长列,应用程序只需在选择列表中包括 ntext、text 或 image 列,并将该列绑定到一个足以容纳适当的数据块的程序变量。然后,应用程序就可以执行该语句,并使用 API 函数或方法将数据逐块检索到绑定的变量中。

  • 若要写入一个长列,应用程序可通过在 ntext、text 或 image 列中要放置值的位置放置一个参数标记 (?),来执行 INSERT 或 UPDATE 语句。参数标记(对 ADO 而言则为参数)将被绑定到一个足以容纳数据块的程序变量上。应用程序会循环地将下一组数据移到绑定的变量中,然后调用 API 函数或方法来写入数据块。这一过程将反复进行,直到整个数据值发送完毕。

使用 text in row

在 SQL Server 中,用户可以在表上启用 text in row 选项,以使该表能够在其数据行中存储 text、ntext 或 image 数据。

若要启用该选项,请执行 sp_tableoption 存储过程,将 text in row 指定为选项名并将 on 指定为选项值。对于 BLOB(一种二进制大型对象,例如 text、ntext 或 image 数据),可以在行中存储的默认最大大小为 256 字节,但是取值范围为从 24 到 7000。若要指定一个非默认的最大大小,可以在取值范围内指定一个整数作为选项值。

在满足以下条件时,数据行可以存储 text、ntext 或 image 字符串:

  • 启用了 text in row

  • 字符串的长度比 @OptionValue 中指定的限制值短

  • 数据行中有足够的可用空间。

在 BLOB 字符串存储在数据行中时,读取和写入 text、ntext 或 image 字符串可以与读取或写入字符和二进制字符串一样快。SQL Server 不必访问不同的页,就可读取或写入 BLOB 字符串。

如果 text、ntext 或 image 字符串比所指定的限制或行中的可用空间大,指针反而将存储在行中。尽管需要满足以下条件,但是在行中存储 BLOB 字符串的条件仍然适用:数据行中必须有足够的空间来存放指针。

有关详细信息,请参阅 sp_tableoption (Transact-SQL)

使用文本指针

除非指定了 text in row 选项,否则 text、ntext 或 image 字符串将存储在数据行以外;而只有这些字符串的文本指针会驻留在数据行中。文本指针指向由内部指针构建的树的根节点,而这些内部指针映射到实际存储 text、ntext 或 image 数据的字符串片断的页。

SQL Server 2000 中的行文本指针不同于 SQL Server 早期版本中的文本指针。行文本指针的行为方式类似于 BLOB 数据的文件句柄;而早期版本文本指针的作用类似于对 BLOB 数据寻址功能。因此,在使用行文本指针时,请记住下列特性:

重要说明重要提示

虽然游标中允许使用行内文本,但不允许使用行内文本指针。如果您尝试声明包含行内文本指针的游标,则 SQL Server 将返回错误 328。

  1. 数值

    在每个数据库中,每个事务最多允许有 1024 个活动的行文本指针。

  2. 锁定

    如果用户获取了活动文本指针,SQL Server 2000 将在第一个用户拥有文本指针时锁定数据行,以确保其他用户不能修改或删除该行。锁将在文本指针变为无效时被释放。若要使文本指针无效,请使用 sp_invalidate_textptr (Transact-SQL)

    当事务的隔离级别为“未提交读”或者数据库处于“只读”模式时,不能使用文本指针来更新 BLOB 值。

    当数据库处于“单用户”模式时,SQL Server 2000 不锁定数据行。

    为举例说明,给出下面的表:

    CREATE TABLE t1 (c1 int, c2 text)
    EXEC sp_tableoption 't1', 'text in row', 'on'
    INSERT t1 VALUES ('1', 'a')
    

    下面的事务将会成功:

    INSERT t1 VALUES ('1','This is text.')
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
    GO
    BEGIN TRAN
    DECLARE @ptr varbinary(16)
    SELECT @ptr = textptr(c2)
    FROM t1
    WHERE c1 = 1;
    READTEXT t1.c2 @ptr 0 5
    COMMIT TRAN
    GO
    

    下面的事务将会失败:

    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
    GO
    BEGIN TRAN
    DECLARE @ptr varbinary(16)
    SELECT @ptr = textptr(c2)
    FROM t1
    WHERE c1 = 1
    WRITETEXT t1.c2 @ptr 'xx'
    COMMIT TRAN
    GO
    
  3. 持续时间

    行文本指针仅在事务内有效。提交事务后,该文本指针将变为无效。

    在某个事务内,当发生下列任一操作时,行文本指针可能无效:

    • 会话结束。

    • 在同一事务中,数据行被删除。(因为获取了数据行锁,因此其他事务无法删除该数据行。)

    • 文本指针所在的表的架构发生更改。使文本指针无效的架构更改操作包括:创建或删除聚集索引、更改或删除表、截断表、通过 sp_tableoption 更改 text in row 选项,以及执行 sp_indexoption

    使用前面的示例,以下脚本可以在 SQL Server 早期版本中运行,但在 SQL Server 2000 中将生成错误。

    DECLARE @ptrval varbinary(16)
    PRINT 'get error here'
    SELECT @ptrval = TEXTPTR(c2)
    FROM t1
    WHERE c1 = 1
    READTEXT t1.c2 @ptrval 0 1
    

    在 SQL Server 2000 中,行文本指针必须在事务内使用:

    BEGIN TRAN
    DECLARE @ptrval varbinary(16)
    SELECT @ptrval = TEXTPTR(c2)
    FROM t1
    WHERE c1 = 1
    READTEXT t1.c2 @ptrval 0 1
    COMMIT
    
  4. NULL 文本

    可以在由 INSERT 生成的 NULL 文本上获取行文本指针。而在以前,只有将 BLOB 更新为 NULL 后才能获得文本指针。

    例如,下列代码在 SQL Server 7.0 中无效,但在 SQL Server 2000 中有效。

    SET TRANSACTION ISOLATION LEVEL READ COMMITTED
    GO
    INSERT INTO t1 VALUES (4, NULL)
    BEGIN TRAN
    DECLARE @ptrval VARBINARY(16)
    SELECT @ptrval = TEXTPTR(c2)
    FROM t1
    WHERE c1 = 4
    WRITETEXT t1.c2 @ptrval 'x4'
    COMMIT
    

    在 SQL Server 7.0 中,必须执行下列操作:

    INSERT INTO t1 VALUES (4, NULL)
    UPDATE t1 
       SET c2 = NULL 
       WHERE c1 = 4
    DECLARE @ptrval VARBINARY(16)
    SELECT @ptrval = TEXTPTR(c2)
    FROM t1
    WHERE c1 = 4
    WRITETEXT t1.c2 @ptrval 'x4'
    

下表汇总了差别。

差别

行文本指针

非行文本指针

数值

在每个数据库中,每个事务最多允许有 1024 个活动的行文本指针。

无限制。

锁定

以 S 方式锁定数据行,直到指针变为无效为止。

当事务为“未提交读”或数据库为“单用户”或“只读”模式时不获取锁。

不锁定数据行。

持续时间

事务或会话结束、删除行或更改表的架构时变为无效。

删除行时变为无效。

NULL 文本

插入 NULL 文本后可立即获取。

只有更新后才能获取。

通过数据库 API 使用 ntext、text 和 image 数据

这一部分概述了数据库 API 处理 ntext、text 和 image 数据的方式:

  • ADO

    ADO 可以将 ntext、text 或 image 列或参数映射为 FieldParameter 对象。使用 GetChunk 方法逐块检索数据,使用 AppendChunk 方法逐块写数据。

  • OLE DB

    OLE DB 使用 ISequentialStream 接口来支持 ntext、text 和 image 数据类型。ISequentialStream::Read 方法逐块读取长数据,ISequentialStream::Write 方法将长数据逐块写入数据库。有关详细信息,请参阅 BLOB 和 OLE 对象

  • ODBC

    ODBC 具有一种称为“执行中的数据”的功能,用来处理 ODBC 数据类型的长数据:SQL_WLONGVARCHAR (ntext)、SQL_LONGVARCHAR (text) 和 SQL_LONGVARBINARY (image)。这些数据类型被绑定到某个程序变量上。然后,就可以调用 SQLGetData 来逐块检索长数据,调用 SQLPutData 来逐块发送长数据。有关详细信息,请参阅管理 Text 和 Image 列

  • DB-Library

    DB-Library 应用程序也将 ntext、text 和 image 列绑定到程序变量。DB-Library 函数 dbtxtptr 用于获取指向数据库中长列出现的位置的指针,dbreadtext 则用来逐块读取长数据。dbwritetextdbupdatetextdbmoretext 等函数用于逐块写入长数据。

    注意注意

    不支持使用 DB-Library 访问行文本。

有关详细信息,请参阅文本与图像函数 (Transact-SQL)