【发布时间】:2016-01-19 13:49:13
【问题描述】:
我正在尝试跟踪是否需要更新某些表。我有一个要监视更改的事件表,还有另一个名为 DictionaryRefresh 的表,它跟踪对该表所做的更改。如果 Events 表被编辑,它的编辑时间将被保存并且比 DictionaryRefresh 表的最后刷新时间晚,因此表明需要刷新。此外,如果将新行添加到 Events 表中,则 DictionaryRefresh 表中还需要关联新条目 - 因此是 LEFT JOIN。
这里是表结构
CREATE TABLE [dbo].[DictionaryRefresh]
(
[LookupKey] [varchar](31) NOT NULL,
[LookupValue] [varchar](255) NOT NULL,
[RecordNumber] [int] NULL,
[RefreshTime] [datetime] NULL,
[EventKey] [varchar](31) NULL,
[MappedLookupKey] [varchar](31) NULL
) ON [PRIMARY]
索引是(遵循 DBEngine Tuning Advisor)
CREATE NONCLUSTERED INDEX [idx_DictionaryRefresh2146B4EB]
ON [dbo].[Ifx_DictionaryRefresh] ([LookupKey] ASC)
CREATE NONCLUSTERED INDEX [idx_DictionaryRefresh51EC6492]
ON [dbo].[Ifx_DictionaryRefresh] ([MappedLookupKey] ASC, [RefreshTime] ASC, [RecordNumber] ASC, [EventKey] ASC)
CREATE NONCLUSTERED INDEX [idx_DictionaryRefreshFCDAD7FA]
ON [dbo].[Ifx_DictionaryRefresh] ([LookupValue] ASC)
事件表如下:
CREATE TABLE [dbo].[Events](
[RecordNumber] [int] NOT NULL,
...
[EventKey] [varchar](31) NOT NULL,
...
[EditTime] [datetime] NULL,
...
PRIMARY KEY CLUSTERED([RecordNumber] ASC)
CREATE NONCLUSTERED INDEX [idxEvents299ADAC8]
ON [dbo].[Events]([EditTime] ASC)
CREATE NONCLUSTERED INDEX [idxEvents5B151A5E]
ON [dbo].[Events]([EventKey] ASC)
现在我正在运行的 SQL 如下 - 需要将近一分钟才能返回。如果我只执行子查询,它会立即返回。
IF EXISTS (
SELECT 1
FROM (
SELECT
e.EventKey AS DictionaryKey
,ISNULL(e.EditTime, '1 Jan 1900 01:00') AS EditTime
,e.RecordNumber AS DictionaryRecordNumber
FROM Events e) d
LEFT JOIN DictionaryRefresh r ON r.RecordNumber = DictionaryRecordNumber
AND r.EventKey = DictionaryKey
AND r.MappedLookupKey = 'M18E2I501'
WHERE r.RefreshTime < d.EditTime
OR r.RecordNumber IS NULL)
BEGIN
PRINT 'TRUE'
END
DictionaryRefresh 表中有大约 130K 行,Events 表中有大约 8K 行
当DictionaryRefresh 表为空或很小时,它会非常快,但会随着 DictionaryRefresh 中行数的增加而减慢,尤其是在没有符合条件的情况下。
这是执行计划。
以及显着的统计数据(索引查找占成本的 94% - 访问的行数实际上是事件表中行数的平方)...
我已经尝试更换了
IF EXISTS
与
IF (SELECT COUNT ...) <> 0
还有
IF (SELECT TOP 1 1 ...) = 1
但似乎没有一个更快。
如果您有任何建议,我将不胜感激。
提前致谢。
S
【问题讨论】:
-
你试过这样 IF EXISTS (SELECT TOP 1 1 FROM events e LEFT JOIN dictionaryrefresh r ON r.RecordNumber = e.DictionaryRecordNumber AND r.EventKey = e.DictionaryKey AND r.MappedLookupKey = 'M18E2I501 ' WHERE r.RefreshTime
-
请提供Events表的表结构,如Dictionaryrefresh
-
谢谢。不幸的是,它花费了大致相同的时间。
-
IF EXISTS 是有效的,因为它只查看记录是否存在。所以如果你有 if exists (select top 1 1 from abc) 或 (select * from abc) 没关系。
-
没有必要在
EXISTS()构造中使用TOP或SELECT 1。服务器知道在找到第一条记录后停止。无论如何,您的设置最让我印象深刻的是您似乎没有任何 unique 索引。除非您的数据非常奇特,否则我建议您至少在使记录可唯一识别的字段上放置一个主键。
标签: sql-server query-optimization