【问题标题】:Count(*) with NText column is very very very slow. Why is it so slow? And how can I improve performance?带有 NText 列的 Count(*) 非常非常非常慢。为什么这么慢?以及如何提高性能?
【发布时间】:2011-01-12 11:32:18
【问题描述】:

我的 SQL Server 2005 数据库出现了一些问题。我有一个带有订单行的表格,每一行都有一个名为XmlDataNTEXT 字段。我想计算所有没有存储信息的字段。我正在使用这个查询:

SELECT Count(*) FROM [OrderLine] WITH(NOLOCK) 
WHERE [XmlData] NOT LIKE '' AND [XmlData] IS NOT NULL 

该表有 230.314 条记录,此计数查询需要几分钟时间。你们中有人知道如何提高性能吗?

注意:我无法将列的类型更改为nvarchar(max) 类型。 NOLOCK 是一位同事的小费。

我期待一些提示和解释。

【问题讨论】:

  • 为什么要用NOT LIKE与空字符串进行比较?
  • 为什么你不能把它改成NVARCHAR(MAX)??这(或将其更改为XML)将是您最好的选择! NTEXT 很乱,很慢,不再受支持 - 摆脱它!
  • 您是否有任何无法更改的系统,这取决于此字段是否为 ntext?或者,如果您解释了为什么此更改会带来好处,您将能够更改其类型?
  • 看起来越来越没有理由不更改为 NVARCHAR(MAX) (这是很多不)。我将研究 NTEXT 的弃用以及 NVARCHAR(MAX) 或 XML 的使用。

标签: sql database sql-server-2005 tsql


【解决方案1】:

为避免昂贵的 LOB 读取,请将 [XmlData] NOT LIKE '' 替换为 DATALENGTH([XmlData])>0 - DATALENGTH 不需要读取每一行的 LOB 值。

另外,正如其他人所建议的:如果可能,使用 nvarchar(max) 代替 ntext。

【讨论】:

  • 是的!我们有一个性能提升。 DataLength 优于 NOT LIKE '' AND IS NOT NULL。
  • 仅供参考:如果您想要更快的 XmlData IS NULL,您需要执行 DATALENGTH([XmlData]) IS NULL。
【解决方案2】:

NTEXT 已弃用,请改用 nvarchar(max)(考虑 xml ...)。

如果您更改列类型,您可以在列上创建索引,因此为列创建统计信息将有助于 SQL 选择使用该索引的最佳方式。

为 XMLData 列创建统计信息,因为这会创建一个值映射,这将显着增加查询的计数类型。

CREATE STATISTICS STATOrderLineXmlData
ON OrderLine (XmlData)
WITH FULLSCAN

根据@Pent 的回答,您应该更改对此的查询: 替换查询:

SELECT Count(*) 
FROM [OrderLine] WITH(NOLOCK) 
WHERE [XmlData] IS NOT NULL 
AND DATALENGTH([XmlData]) > 0

如果您要更改 nvarchar(max) 的列类型,请检查 this Link。 该链接包含有关您必须执行的一些棘手更新的信息,以便在列更改后获得性能。

【讨论】:

  • @Gabriel 这是确切的查询
  • @Kees 你为 ntext 字段创建了统计信息吗?
  • @Gabrial,不,我没有为该领域创建任何统计数据。
  • @Kees 请创建它,您可以在我的回答中获取脚本。
  • 统计只影响查询计划,不影响实际的执行速度,所以在这里他们没有帮助。 COUNT 查询不在统计数据上运行,而是在实际数据上运行。
【解决方案3】:

首先,此查询将涉及表扫描。 230K 行会很慢。您可以尝试将 NOT LIKE 替换为 Length(XmlData) = 0,但我认为这不会有太大帮助。另一方面,我不确定 Length 函数是否适用于 NText 数据类型。我不认为它有,现在我想起来了。

底线是表扫描很慢,处理 NText 数据类型很慢。所以你在这里有一个糟糕的组合。除非可以更改数据类型,否则我认为这里没有太大的改进空间。

而且,我相信您可能已经意识到使用 WITH NOLOCK 会带来读取脏数据的风险?是的,它可以帮助提高性能,但它不是免费的。您可能正在阅读未提交的更改。

【讨论】:

  • 长度解决方案在执行计划中给出了相同的结果。看来table scan还是最差的: Used: SELECT Count(*) FROM [OrderLine] WITH(NOLOCK) WHERE len(XmlData] as nvarchar(1))) = 0 读取脏数据这个没问题数。
猜你喜欢
  • 2021-05-24
  • 1970-01-01
  • 1970-01-01
  • 2010-10-24
  • 1970-01-01
  • 2013-06-29
  • 2020-06-11
  • 1970-01-01
  • 2012-06-30
相关资源
最近更新 更多