选择列会影响执行计划吗?

时间:2012-08-24 09:39:53

标签: sql sql-server sql-server-2008 tsql sql-execution-plan

我有一个像这样的查询。它有一个使用我期望的索引的执行计划,直到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

好:

enter image description here

为:

enter image description here

3 个答案:

答案 0 :(得分:1)

通过这种设置 - 不知道详细的表格结构(还) - 你绝对应该:

  • 在你的桌子上有一个聚集索引dbo.Lx_AuditColumn(像INT IDENTITY这样的东西几乎是完美的)
  • Lx_AuditColumn.auditTableFK上的非聚集索引,以加快JOIN和参照完整性检查
  • Lx_AuditColumn.AuditColumnPK上的非聚集索引(当然,除非那已经是聚集的PK!)
  • Lx_AuditTable.CreatedDate
  • 上的非聚集索引

另外:您应该使用正确的ANSI / ISO标准INNER JOIN语法(而不是仅使用逗号分隔的表列表进行选择 - 有关此主题的背景信息,请参阅Bad habits to kick : using old-style JOINs) - 使用此查询:

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

答案 1 :(得分:0)

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

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

INNER HASH JOIN ...

这将强制散列连接也会修复连接顺序。

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

答案 2 :(得分:0)

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