我有一个像这样的查询。它有一个使用我期望的索引的执行计划,直到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
好:
为:
答案 0 :(得分:1)
通过这种设置 - 不知道详细的表格结构(还) - 你绝对应该:
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(即强制设计者创建一个新表并复制数据),然后删除额外的列。也许弹出服务器或其他东西可以解决这个问题,但我能够做到这一点就像没有弹出服务器。