简介

本文介绍了 SQL Server 错误 2570年,导致错误的原因和如何解决问题。

详细信息

DATA_PURITY 检查

在 SQL Server 2005 中,一个新选项,DATA_PURITY,得到了 DBCC CHECKDB 和所对应的行命令。当启用此选项执行 DBCC CHECKDB 或对应的命令时,该命令将执行"数据纯度"验证上的表或数据库中的表的所有行中每个列的值。执行这些新的检查以确保存储在列中的值是有效 (即,值不是域范围外与该列的数据类型)。执行验证的性质取决于列的数据类型。以下的非详尽列表提供了一些示例︰

列数据类型

数据执行的验证类型

Unicode 字符

数据的长度应该是 2 的倍数。

日期时间

天字段应在 1753 年 1 月 1 日和 12 月 31 日之间到 9999。时间字段必须早于"11:59:59:999 PM"。

真实和浮动

检查存在无效浮点值如 SNAN、 QNAN、 NINF,ND,PD、 PINF。

不是所有的数据类型的列数据的有效性检查。只可能有一个存储的值超出了范围,进行检查。例如, tinyint数据类型的有效范围是 0 到 255,并且存储在单个字节 (它只能存储从 0 到 255 之间的值),因此检查该值不必要。

对于所有数据库未启用自动数据纯度验证检查。启用检查取决于几个因素︰

  • 对于 SQL Server 2005 及更高版本中创建的数据库,这些检查默认情况下启用,并且不能禁用,因此使用 DATA_PURITY 选项执行 DBCC CHECKDB 或所对应的行命令不起作用。

  • 在早期版本的 SQL Server,如 SQL Server 2000年,SQL Server 7.0 中和版本升级到 SQL Server 2005 中,创建的数据库的默认情况下未启用这些检查。为了执行这些检查,您必须指定的 DBCC CHECKDB 或所对应的行命令中的 DATA_PURITY 选项。这可能会导致以下两种情况︰

    • DBCC 命令完成并报告数据库处于干净,包括所有数据纯度检查。这一事实记录在数据库标头中。所有后续的 DBCC CHECKDB 或所对应的行命令执行会注意到此信息,并将自动执行数据纯度检查,因为会创建对 SQL Server 2005 的数据库。换句话说,一旦知道数据库是"干净",始终执行数据纯度检查。

    • DBCC 命令成功完成,但是报告有关数据不一致的问题。如果出现这种情况,将必须清除要移除不一致的数据库,然后尝试再次执行 DBCC 命令。您必须指定 DATA_PURITY 选项 DBCC 命令,直到数据库被报告为干净。

  • 如果执行 DBCC CHECKDB 或所对应的行命令时指定 PHYSICAL_ONLY 选项,则不执行数据纯度检查。

症状

无效或超出范围的数据可能存储在早期版本的 SQL Server 数据库中,原因如下︰

  • 无效数据时显示在源时使用大容量插入方法,如 bcp 实用工具。

  • 通过向 SQL Server 发出的 RPC 事件调用传递了无效数据。

  • 其他可能导致左物理数据损坏的列的值处于无效状态。

如果一个表的列中有无效的数据,可能会遇到问题取决于对无效数据执行的操作的类型。但是,也很可能会出现任何问题,直到您在 SQL Server 2005 及更高版本上执行 DBCC CHECKDB 或所对应的行命令时才会发现无效数据。

一些您可能会注意到由于存在无效数据的症状包括 (但并不局限于)︰

  • 访问冲突或其他类型的对受影响的列执行的查询在执行时的异常。

  • 对受影响的列执行的查询所返回的结果不正确。

  • 错误或正在对受影响的列生成统计信息时出现问题。

  • 类似于下面的错误消息︰

    Msg 9100,级别 23 状态 2 行 1 检测到索引可能已损坏。运行 DBCC CHECKDB。

DATA_PURITY 问题报告

当执行 DBCC CHECKDB 或所对应的行命令与 DATA_PURITY 选项处于启用状态 (或自动执行检查数据纯度) 和无效数据由 DBCC 命令检查表中存在,DBCC 输出中包括更多的消息,以表明数据方面的问题。表示数据的纯度问题一些示例错误消息如下所示︰

"Account_history"的 DBCC 结果。
Msg 2570,级别 16 状态 2,第 1 行
页面 (1:1073)、 插槽 33 对象 ID 1977058079 中,索引 ID 0、 分区 ID 129568478265344,分配单元 ID 129568478265344 (类型"行内数据")。"Account_name_japan"列的值不在数据类型"nvarchar"的范围。更新为合法值列。

Msg 2570,级别 16 状态 2,第 1 行
页面 (1:1156)、 插槽 120 对象 ID 1977058079 中,索引 ID 0、 分区 ID 129568478265344,分配单元 ID 129568478265344 (类型"行内数据")。"Account_name_japan"列的值不在数据类型"nvarchar"的范围。更新为合法值列。
对象"account_history"的 1080年页中有 153137 行。
CHECKDB 表"account_history"(对象 ID 1977058079) 中找到 0 个分配错误和 338 一致性错误。
CHECKDB 数据库 BadUnicodeData 中找到 0 个分配错误和 338 一致性错误。
DBCC 执行完毕。如果 DBCC 输出错误消息,请与您的系统管理员联系。

DBCC"表 1"的结果。
Msg 2570,级别 16 状态 3,第 1 行
页面 (1:154)、 插槽 0 中的对象 ID 2073058421 中,索引 ID 0,分区 ID 72057594038321152,分配单元 ID 72057594042318848 (类型"行内数据")。"第 2 列"列中的值不在数据类型"真正"的范围。更新为合法值列。
2 页对象"表 1"中有四行。
CHECKDB 找到 0 分配错误和表"表 1"中的 1 的一致性错误 (对象 ID 2073058421)。
CHECKDB 数据库 realdata 中找到 0 个分配错误和 1 一致性错误。DBCC 执行完毕。如果 DBCC 输出错误消息,请与您的系统管理员联系。

DBCC 结果"表 2"。
Msg 2570,级别 16 状态 3,第 1 行
页面 (1:155)、 插槽 0 中的对象 ID 2105058535 中,索引 ID 0,分区 ID 72057594038452224,分配单元 ID 72057594042449920 (类型"行内数据")。"第 2 列"列中的值超出了范围为数据类型"十进制"。更新为合法值列。
1 页对象"表 2"中有四行。
CHECKDB 找到 0 分配错误和表"表 2"中的 1 的一致性错误 (对象 ID 2105058535)。
CHECKDB 数据库 realdata 中找到 0 个分配错误和 1 一致性错误。DBCC 执行完毕。如果 DBCC 输出错误消息,请与您的系统管理员联系。

DBCC table3 的结果。
Msg 2570,级别 16 状态 3,第 1 行
页面 (1:157)、 插槽 0 中的对象 ID 2121058592 中,索引 ID 0,分区 ID 72057594038517760,分配单元 ID 72057594042515456 (类型"行内数据")。"第 2 列"列中的值超出了范围为数据类型"日期时间"。更新为合法值列。
1 页对象"table3"中有三行。
CHECKDB 找到 0 分配错误和 1 一致性错误 table3 表 (对象 ID 2121058592)。
CHECKDB 数据库 realdata 中找到 0 个分配错误和 1 一致性错误。DBCC 执行完毕。如果 DBCC 输出错误消息,请与您的系统管理员联系。

对于每个行包含无效的列的值,生成 2570年错误。

修复数据纯度问题

不能使用任何 DBCC 修复选项修复 2570年错误。这是因为很难 DBCC 来确定应使用什么值来替换无效的列的值。因此,必须手动更新列的值。

若要进行手动更新,您必须查找出现问题的行。有两种方法来实现此目的。

  • 对执行查询的表中包含无效的值来查找包含无效值的行。

  • 使用从 2570年错误的信息来标识包含无效值的行。

我们将讨论这两种方法在下面,使用示例查找包含无效数据的行。

一旦您找到正确的行,决策需要将用来替换现有的无效数据的新值。这一决定将不得不非常小心地根据适用于应用程序的值的范围作出以及是什么使特定行的数据的逻辑意义。您可以选择是︰

  • 如果您知道它应该是什么值,则将其设置为特定值。

  • 将其设置为可接受的默认值。

  • 将列的值设置为 NULL。

  • 将列的值设置为列中的数据类型的最大值或最小值。

  • 如果您觉得不包含有效的值为列任何使用的不是特定的行,您可以完全删除该行。

查找使用 T SQL 查询无效值的行

您需要查找具有无效值的行执行的查询的类型取决于列报告问题的数据类型。如果您看一下 2570年错误消息,您会注意到信息可帮助您实现这两个重要的部分。在下面的示例中,"account_name_japan"列的值不在范围内的数据类型"nvarchar。"我们可以轻松地标识有问题,以及涉及到的列的数据类型的列。因此,一旦您知道数据类型,并且所涉及的列中,可以建立查询来查找包含无效值,则该列的行,选择的列需要标识该行 (如 WHERE 子句中的谓词),对于任何进一步更新或删除。

Unicode 数据类型:

SELECT col1 ,DATALENGTH(account_name_japan) as Length ,account_name_japan 
FROM account_history
WHERE DATALENGTH(account_name_japan) % 2 != 0


浮点数据类型:

-- Change col1 to your actual primary key column(s), col2 to the column from the 2570 error, table1 to the table from the CHECKDB output

SELECT col1, col2 FROM table1
WHERE col2<>0.0 AND (col2 < 2.23E-308 OR col2 > 1.79E+308) AND (col2 < -1.79E+308 OR col2 > -2.23E-308)


真正的数据类型:

-- Change col1 to your actual primary key column(s), col2 to the column from the 2570 error, table1 to the table from -- the CHECKDB output

SELECT col1, col2 FROM testReal
WHERE col2<>0.0 AND (col2 < CONVERT(real,1.18E-38) OR col2 > CONVERT(real,3.40E+38)) AND (col2 < CONVERT(real,-3.40E+38) OR col2 > CONVERT(real,-1.18E-38))
ORDER BY col1; -- checks for real out of range

小数和数值数据类型:

SELECT col1 FROM table2
WHERE col2 > 9999999999.99999
OR col1 < -9999999999.99999

请记住,您将需要调整根据精度和与其定义十进制或数字列的小数位数的值。在上面的示例中,列中被定义为 col2 decimal(15,5)。

日期时间数据类型:
您将需要执行两个不同的查询来标识包含无效的日期时间列的值的行。

SELECT col1 FROM table3
WHERE col2 < '1/1/1753 12:00:00 AM' OR col2 > '12/31/9999 11:59:59 PM'

SELECT col1 FROM table3 WHERE
((DATEPART(ms,col2)+ (1000*DATEPART(s,col2)) + (1000*60*DATEPART(mi,col2)) + (1000*60*60*DATEPART(hh,col2)))/(1000*0.00333))
> 25919999

具有无效值使用的物理位置中查找的行︰

如果您找不到使用上面讨论的 T SQL 方法感兴趣的行,您可以使用此方法。在 2570年错误消息中,将打印包含无效值的行的物理位置。例如,请看下面的消息︰

页面 (1:157)、 插槽 0 中的对象 ID 2121058592 中,索引 ID 0,分区 ID 72057594038517760,分配单元 ID 72057594042515456 (类型"行内数据")。"第 2 列"列中的值超出了范围为数据类型"日期时间"。更新为合法值列。

此消息中,您将注意到的信息︰ 页面 (1:157) 的插槽 0。这是您需要标识行的信息。FileId 为 1,PageInFile 是 157,开关为 0。一旦您知道此信息,您需要执行该命令,如下︰

DBCC TRACEON ( 3604 )
DBCC PAGE ( realdata , 1 , 157 , 3 )

此命令将打印页的全部内容。DBCC 页命令的参数是︰

  • 数据库名称

  • FileId

  • PageInFile

  • 打印选项

一旦执行此命令时,您会看到输出包含类似于以下格式的信息︰

Slot 0  Offset 0x60 Length 19 Record Type = PRIMARY_RECORD Record
Attributes = NULL_BITMAP Memory Dump @0x44D1C060 00000000: 10001000 01000000
ffffffff ffffffff †................ 00000010:
0200fc†††††††††††††††††††††††††††††††... Slot 0 Column 0 Offset 0x4 Length 4 col1 = 1 Slot 0 Column 1 Offset 0x8 Length 8 col2 = Dec 31 1899 19:04PM Slot 1 Offset 0x73 Length 19 Record Type = PRIMARY_RECORD Record
Attributes = NULL_BITMAP Memory Dump @0x44D1C073 00000000: 10001000 02000000
0ba96301 f8970000 †..........c..... 00000010:
0200fc†††††††††††††††††††††††††††††††... Slot 1 Column 0 Offset 0x4 Length 4
col1 = 2 Slot 1 Column 1 Offset 0x8 Length 8 col2 = Jul 8 2006 9:34PM Slot 2
Offset 0x86 Length 19 Record Type = PRIMARY_RECORD Record Attributes =
NULL_BITMAP Memory Dump @0x44D1C086 00000000: 10001000 03000000 0ba96301
f8970000 †..........c..... 00000010: 0200fc†††††††††††††††††††††††††††††††...
Slot 2 Column 0 Offset 0x4 Length 4 col1 = 3 Slot 2 Column 1 Offset 0x8 Length
8 col2 = Jul 8 2006 9:34PM

在此输出中可以清楚地看到您感兴趣的行的列值。在这种情况下,您需要存储在插槽 0 中的页上的行。从错误消息中,您知道该第 2 列是一个问题。因此可以采取 col1 值为 0 的插槽并将其用作您的更新语句的 WHERE 子句中的谓语或删除语句。

警告我们建议您使用第一种方法 (即,使用 T SQL 查询以查找所需的信息)。只有作为最后的手段使用 DBCC 页命令。采用极其小心,而在生产环境中使用此命令。最好恢复生产数据库在测试服务器上,则获取所有使用 DBCC 页所需的信息,然后执行在生产服务器上的更新。与以往一样,一定要留有备份准备,以防出现故障并且您需要还原到早期的数据库副本。

参考资料

有关 DBCC CHECKDB 语句的详细信息,请参阅下面的 Microsoft 开发人员网络 (MSDN) 的网站上的"DBCC CHECKDB (事务处理 SQL)"主题︰

http://msdn2.microsoft.com/en-us/library/ms176064.aspx在 SQL Server 2000年中的已知问题的详细信息,请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章︰

900335解决︰ 如果索引包含浮点数据类型真正的数据类型,并且此数据类型包含 NaN 值的 SQL Server 2000年数据库自动恢复操作可能不会成功

有关 RPC 事件的详细信息,参见"调用存储过程 (OLE DB)"上下面的 MSDN 网站︰

http://msdn2.microsoft.com/en-us/library/aa198358(SQL.80).aspx有关不同数据类型的详细信息,参见"调用存储过程 (OLE DB)"上下面的 MSDN 网站︰

http://msdn2.microsoft.com/en-us/library/ms187752.aspx有关浮动点值约定的详细信息,请访问下面的 Intel 网站︰

http://www.intel.com/design/pentiumii/manuals/243191.htmMicrosoft 提供的第三方联系人信息,以帮助您查找技术支持。此联系信息如有更改,恕不另行通知。Microsoft 不能保证第三方联系信息的准确性。

Need more help?

Expand your skills
Explore Training
Get new features first
Join Microsoft Insiders

Was this information helpful?

How satisfied are you with the translation quality?
What affected your experience?

Thank you for your feedback!

×