2

我有一个简单的查询:

select top 10 * 
FROM Revision2UploadLocations r2l
inner join Revisions r on r2l.RevisionId = r.Id
INNER JOIN [Databases] [D] on [R].[DatabaseId] = [D].[Id]
INNER JOIN [SqlServers] [S] on [D].[InstanceId] = [S].[Id]
where --r.ValidationStatus in (2, 3) and 
r2l.[ChecksumWasSent] = 0 AND r2l.Status = 2

该查询通常执行 0.5s: 执行计划1

但是具有未注释条件的相同查询执行了 5s (!!!) 并且有一个非常奇怪的执行计划 (Revisions 和 SqlServers 虽然没有链接列并且最具选择性的条件 "r2l.[ChecksumWasSent] = 0 AND r2l .Status = 2" 在查询处理结束时执行: 执行计划2

ValidationStatus 是普通的 int 非空列。列 Revision2UploadLocations.RevisionId、Revisions.DatabaseId、Databases.InstanceId 已编入索引。以下是表的说明:

CREATE TABLE [SqlServers]
(
    [Id] int identity(1,1) NOT NULL CONSTRAINT PK_SqlServers PRIMARY KEY,
...
)

CREATE TABLE [Databases](
    [Id] int identity(1,1) NOT NULL CONSTRAINT PK_Databases PRIMARY KEY,
    [InstanceId] int NOT NULL,
    [Name] nvarchar(128) NOT NULL,
...
    CONSTRAINT FK_Databases_SqlServers FOREIGN KEY ([InstanceId]) REFERENCES [SqlServers]([Id])
)

CREATE INDEX [IX_Databases_DatabaseId] ON [Databases] ([InstanceId] ASC)

CREATE TABLE [Revisions]
(
    [Id] int identity(1, 1) NOT NULL,
    [DatabaseId] int NOT NULL,
    [BackupStatus] tinyint NOT NULL,
    [ValidationStatus] tinyint NOT NULL,
...
    CONSTRAINT PK_Revisions PRIMARY KEY([Id]),
    CONSTRAINT FK_Revisions_Databases FOREIGN KEY ([DatabaseId]) REFERENCES [Databases]([Id])
)

CREATE INDEX [IX_Revisions_DatabaseId] ON [Revisions] ([DatabaseId] ASC)

CREATE TABLE [Revision2UploadLocations]
(
    [Id] int NOT NULL IDENTITY (1, 1) CONSTRAINT PK_Revision2UploadLocations PRIMARY KEY,
    [Status] int NOT NULL,
    RevisionId int NOT NULL,
    [ChecksumWasSent] bit NOT NULL,
    CONSTRAINT FK_r2l_Revisions FOREIGN KEY ([RevisionId]) REFERENCES [Revisions]([Id])
)

CREATE INDEX [IX_Revision2UploadLocations_RevisionId] ON [Revision2UploadLocations] ([RevisionId] ASC)

如何提高此查询的性能?

编辑现在我有更多详细信息:一些表(SqlServers 和数据库)有 1-10 条记录,但 Revisions 和 Revision2UploadLocations)有 500K+ 记录,因此查询优化决定使用全扫描而不是索引搜索小表并首先使用它。 查询性能调优(SQL Server Compact)

小表格是其内容适合一个或几个数据页的表格。避免索引非常小的表,因为执行表扫描通常更有效。

作为临时解决方案,我尝试使用查询提示FORCE ORDER查询提示(SQL Server Compact) 和响应时间从 5 秒减少到 0.5 秒。

但我认为这不是一个好的解决方案。

4

2 回答 2

0

我过去发现,如果我首先将查询的第一部分插入到临时表中,并带有要进一步过滤的字段(“ValidationStatus”],然后查询你的临时表,性能/速度会好得多。所以最初的查询是这样的:

select * 
into #tmp
FROM Revision2UploadLocations r2l
inner join Revisions r on r2l.RevisionId = r.Id
INNER JOIN [Databases] [D] on [R].[DatabaseId] = [D].[Id]
INNER JOIN [SqlServers] [S] on [D].[InstanceId] = [S].[Id]
where --r.ValidationStatus in (2, 3) and 
r2l.[ChecksumWasSent] = 0 AND r2l.Status = 2

那么最终的选择将是:

select * from #tmp 
where ValidationStatus in (2,3)

不需要索引,而且我知道优化器并不总是工作很奇怪,但是这种方法在过去对我有用几次。

于 2015-10-06T13:30:25.457 回答
0

Geoffrey 的解决方案没有给您预期的结果。第一条语句选择 10 行,不保证它们的 r.ValidationStatus 为 2 或 3。所以最后,您可以获得少于 10 行(甚至根本没有行)。我认为您可以将查询重写为:

SELECT top 10 *     
FROM Revisions r
  INNER JOIN Revision2UploadLocations r2l 
    ON r2l.RevisionId = r.Id
      AND r2l.[ChecksumWasSent] = 0 
      AND r2l.Status = 2
  INNER JOIN [Databases] [D] on [D].[Id] = [R].[DatabaseId]
  INNER JOIN [SqlServers] [S] on [S].[Id] = [D].[InstanceId]
WHERE r.ValidationStatus in (2, 3)

如果 r2l.[ChecksumWasSent] 数据类型是位(布尔值):

  • 0大于1,可以在RevisionId + Status上创建索引
  • 1 比 0 多得多,您可以创建和定义 RevisionId + ChecksumWasSent + Status
于 2015-10-07T08:18:28.020 回答