2

我有一个这样的查询。它有一个使用我期望的索引的执行计划,直到 SELECT 返回的数据量(即字符数)超过边界。那时,计划不再使用索引,查询速度慢了 100 多倍。

如果我使用NVARCHAR(203),它很快。NVARCHAR(204)是缓慢的。此外,当它不使用索引时,它会完全烧毁 CPU。至少在我看来这是一个数据大小问题,但我正在寻找任何见解。

我已将 oldValueString 和 newValueString 更改为 NVARCHAR(255) 并且情况有所好转,但我仍然无法查询所有列而不会丢失计划中的索引。

SELECT
   [Lx_AuditColumn].[auditColumnPK],
   CONVERT(NVARCHAR(204), [Lx_AuditColumn].[newValueString])
FROM
   [dbo].[Lx_AuditColumn] [Lx_AuditColumn],
   [dbo].[Lx_AuditTable] [Lx_AuditTable]
WHERE
   [Lx_AuditColumn].[auditTableFK] = [Lx_AuditTable].[auditTablePK]
AND
   [Lx_AuditTable].[createdDate] >=  @P1
AND
   [Lx_AuditTable].[createdDate] <=  @P2
ORDER BY
   [Lx_AuditColumn].[auditColumnPK] DESC

这是表的基本结构(我消除了一些索引和 FK 约束)。

CREATE TABLE [dbo].[Lx_AuditTable]
(
   [auditTablePK] [int] NOT NULL IDENTITY(1, 1) ,
   [firmFK] [int] NOT NULL ,
   [auditMasterFK] [int] NOT NULL ,
   [codeSQLTableFK] [int] NOT NULL ,
   [objectFK] [int] NOT NULL ,
   [projectEntityID] [int] NULL ,
   [createdByFK] [int] NOT NULL ,
   [createdDate] [datetime] NOT NULL ,
   CONSTRAINT [Lx_PK_AuditTable_auditTablePK] PRIMARY KEY CLUSTERED
   (
      [auditTablePK]
   ) WITH FILLFACTOR = 90
)
GO

CREATE INDEX [Lx_IX_AuditTable_createdDatefirmFK]
   ON [dbo].[Lx_AuditTable]([createdDate], [firmFK])
   INCLUDE ([auditTablePK], [auditMasterFK])
   WITH (FILLFACTOR = 90, ONLINE = OFF)
GO

CREATE TABLE [dbo].[Lx_AuditColumn]
(
   [auditColumnPK] [int] NOT NULL IDENTITY(1, 1) ,
   [firmFK] [int] NOT NULL ,
   [auditTableFK] [int] NOT NULL ,
   [accessorName] [nvarchar] (100) NOT NULL ,
   [dataType] [nvarchar] (20) NOT NULL ,
   [oldValueNumber] [int] NULL ,
   [oldValueString] [nvarchar] (4000) NULL ,
   [newValueNumber] [int] NULL ,
   [newValueString] [nvarchar] (4000) NULL ,
   [newValueText] [ntext] NULL ,
   CONSTRAINT [Lx_PK_AuditColumn_auditColumnPK] PRIMARY KEY CLUSTERED
   (
      [auditColumnPK]
   ) WITH FILLFACTOR = 90 ,
   CONSTRAINT [Lx_FK_AuditColumn_auditTableFK] FOREIGN KEY
   (
      [auditTableFK]
   ) REFERENCES [dbo].[Lx_AuditTable] (
      [auditTablePK]
   )
)
GO

CREATE INDEX [Lx_IX_AuditColumn_auditTableFK]
   ON [dbo].[Lx_AuditColumn]([auditTableFK])
   WITH (FILLFACTOR = 90, ONLINE = OFF)
GO

好的:

在此处输入图像描述

坏的:

在此处输入图像描述

4

3 回答 3

1

使用此设置 - 在不详细了解表结构的情况下(还) - 您绝对应该:

  • 在您的表 dbo.Lx_AuditColumn 上有一个良好INT IDENTITY的聚集索引(类似 a的东西几乎是完美的)
  • 一个非聚集索引Lx_AuditColumn.auditTableFK来加速 JOIN 和参照完整性检查
  • 上的非聚集索引Lx_AuditColumn.AuditColumnPK(当然,除非那已经是聚集的 PK!)
  • 非聚集索引Lx_AuditTable.CreatedDate

另外:您应该使用正确的 ANSI/ISO 标准INNER JOIN语法(而不是仅使用逗号分隔的表列表来选择 - 请参阅要踢的坏习惯:使用旧式 JOIN获取有关此主题的背景信息) - 使用此查询:

SELECT
   [Lx_AuditColumn].[auditColumnPK],
   CONVERT(NVARCHAR(204), [Lx_AuditColumn].[newValueString])
FROM
   [dbo].[Lx_AuditColumn] [Lx_AuditColumn]
INNER JOIN
   [dbo].[Lx_AuditTable] [Lx_AuditTable] ON [Lx_AuditColumn].[auditTableFK] = [Lx_AuditTable].[auditTablePK]
WHERE
   [Lx_AuditTable].[createdDate] >=  @P1
   AND
   [Lx_AuditTable].[createdDate] <=  @P2
ORDER BY
   [Lx_AuditColumn].[auditColumnPK] DESC
于 2012-08-24T09:53:47.273 回答
0

我将 oldValueString 和 newValueString 更改为 NVARCHAR(255) 并且情况有所好转。但是,在我用缩短的列强行重新创建表之后,事情才恢复“正常”。我添加了一个伪造的 nvarchar(10) 列,使用设计模式将其转换为 int(即强制设计器创建新表并复制数据),然后删除额外的列。也许弹跳服务器或其他东西可以解决这个问题,但我能够像这样在不弹跳服务器的情况下做到这一点。

于 2012-08-26T06:07:35.300 回答
0

虽然我无法为这个问题提供一个优雅的解决方案(除了尝试索引、统计、索引视图等常用方法),但我可以破解这个问题:

将查询转换为使用JOIN语法并应用提示:

INNER HASH JOIN ...

这将强制哈希连接也修复连接顺序。

这不好,因为 SQL Server 不能再适应不断变化的架构和数据。

于 2012-08-24T19:07:05.483 回答