简单条件分解查询优化器及其性能

时间:2015-10-06 11:39:59

标签: performance sql-server-ce sql-server-ce-4 sql-tuning

我有一个简单的查询:

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.5秒: execution plan 1

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

ValidationStatus是普通的int非null列。 列版本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 +记录,因此查询优化决定使用全扫描而不是索引搜索小表并首先采用它。 Query Performance Tuning (SQL Server Compact)

  

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

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

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

2 个答案:

答案 0 :(得分: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)

不需要索引,我知道优化器并不总是有效,但这种方法在过去几次对我有用。

答案 1 :(得分:0)

Geoffrey的解决方案并没有给你预期的结果。 第一个语句选择10行没有garant,他们的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]数据类型为bit(boolean),则为:

  • more 0 than 1,您可以在RevisionId + Status
  • 上创建索引
  • 非常多于1,你可以创建和修改版本ID + ChecksumWasSent +状态