【发布时间】:2014-08-26 15:03:37
【问题描述】:
我在数据库中有以下表格,大约有 1000 万条记录(未来可能会增加一倍):
create table PropertyOwners (
[Key] int not null primary key,
PropertyKey int not null,
BoughtDate DateTime,
OwnerKey int not null
)
go
上表包含所有者在特定时间拥有的所有财产,我想获取当前拥有超过一定数量财产的所有者,比如说一次超过 1000 个财产。我编写了两个不同的查询,一个使用“Rank”,另一个使用“Left join with own table”。
使用排名(大约需要 4 秒):
select OwnerKey, COUNT(1) PropertyCount
from (
select PropertyKey, OwnerKey, BoughtDate,
RANK() over (partition by PropertyKey order by BoughtDate desc) as [Rank]
from dbo.PropertyOwners
) result
where [Rank]=1
group by OwnerKey
having COUNT(1)>1000
对同一张表使用左连接(大约需要 10 秒):
select OwnerKey, COUNT(1) PropertyCount
from (
select po.PropertyKey, po.OwnerKey, po.BoughtDate
from dbo.PropertyOwners po
left join dbo.PropertyOwners lo on lo.PropertyKey = po.PropertyKey
and lo.BoughtDate > po.BoughtDate
where lo.PropertyKey is null
) result
group by OwnerKey
having COUNT(1)>1000
这两个查询时间都是不可接受的,因为要花这么多时间,谁能帮我重写查询。我的表有以下索引:
CREATE NONCLUSTERED INDEX [IX_PropertyKey_BounghtDate] ON [dbo].[PropertyOwners]
(
[PropertyKey] ASC,
[BoughtDate] DESC
)
INCLUDE ( [OwnerKey]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
【问题讨论】:
-
查看您的查询计划。它可能根本没有使用您的索引。此外,您的左连接查询看起来很奇怪。请解释关系表的实际含义 - 进行自联接似乎没有意义。以及为什么当您拥有 PropertyKey 和 OwnerKey 时会有一个 [Key] 字段 - 它们的组合应该是您的主键(除非您有所有权的开始/结束日期)......
-
看起来您在一组相当独特的字段上构建了一个非聚集索引,考虑到聚合,此查询可能不会被此查询使用。
PropertyKey上的非聚集索引可能会提高性能,但执行计划应该为您提供所需的所有洞察力。分析/窗口函数通常比在查询中引入额外的连接更快。 -
我们可以忽略[Key]字段,PropertyKey、OnwerKey、BoughtDate的组合是唯一的,可以复合PK。我检查了执行计划,查询使用的是“索引扫描”而不是“索引搜索”。我已经尽力尝试不同的索引组合但没有成功,这就是我在这里提出问题的原因。左连接查询是选择每个属性的记录,并使用 BoughtDate 检查为每个属性获取最新的记录。
标签: sql sql-server sql-server-2008