我试图从正在访问具有约2.5亿条记录的表的查询中获得更多性能。从我对实际(未估计)执行计划的阅读中,第一个瓶颈是如下查询:
select
b.stuff,
a.added,
a.value
from
dbo.hugetable a
inner join
#smalltable b on a.fk = b.pk
where
a.added between @start and @end;
有关所涉及的表和索引的定义,请参见下文。
执行计划表明在#smalltable上使用了一个嵌套循环,并且对largetable的索引扫描已执行480次(对于#smalltable中的每一行)。这对我来说似乎是倒退的,因此我尝试强制使用合并联接:
select
b.stuff,
a.added,
a.value
from
dbo.hugetable a with(index = ix_hugetable)
inner merge join
#smalltable b with(index(1)) on a.fk = b.pk
where
a.added between @start and @end;
有问题的索引(有关完整定义,请参见下文)涵盖fk列(连接谓词),按升序添加(在where子句中使用)和id(无用),并包括value。
但是,当我这样做时,查询从2 1/2分钟扩展到超过9分钟。我希望这些提示能够强制执行更高效的联接,该联接仅对每个表进行一次传递,但显然不会。
欢迎任何指导。如果需要,提供其他信息。
更新(2011/06/02)
重新组织了表上的索引之后,我取得了显着的性能进步,但是在汇总大表中的数据时遇到了新的障碍。结果是按月汇总,当前看起来如下所示:
select
b.stuff,
datediff(month, 0, a.added),
count(a.value),
sum(case when a.value > 0 else 1 end) -- this triples the running time!
from
dbo.hugetable a
inner join
#smalltable b on a.fk = b.pk
group by
b.stuff,
datediff(month, 0, a.added);
目前,hugetable具有一个聚集索引pk_hugetable (added, fk)
(主键)和一个非聚集索引ix_hugetable (fk, added)
。
如果没有上面的第4列,那么优化器将像以前一样使用嵌套循环联接,使用#smalltable作为外部输入,并使用非聚集索引搜索作为内部循环(再次执行480次)。我担心的是估计行数(12,958.4)与实际行数(74,668,468)之间的差异。这些搜索的相对成本为45%。但是,运行时间不到一分钟。
在第4列中,运行时间飙升至4分钟。这次它以相同的相对成本(45%)在聚簇索引上进行搜索(2次执行),通过哈希匹配(30%)进行聚合,然后在#smalltable(0%)上进行哈希联接。
我不确定我下一步的行动。我担心的是,日期范围搜索或连接谓词都无法保证,甚至无法保证所有结果都将大大减少结果集。在大多数情况下,日期范围只会减少记录的10-15%,而fk上的内部联接可能会过滤掉20-30%。
根据遗嘱A的要求,以下结果sp_spaceused
:
name | rows | reserved | data | index_size | unused
hugetable | 261774373 | 93552920 KB | 18373816 KB | 75167432 KB | 11672 KB
#smalltable定义为:
create table #endpoints (
pk uniqueidentifier primary key clustered,
stuff varchar(6) null
);
虽然dbo.hugetable定义为:
create table dbo.hugetable (
id uniqueidentifier not null,
fk uniqueidentifier not null,
added datetime not null,
value decimal(13, 3) not null,
constraint pk_hugetable primary key clustered (
fk asc,
added asc,
id asc
)
with (
pad_index = off, statistics_norecompute = off,
ignore_dup_key = off, allow_row_locks = on,
allow_page_locks = on
)
on [primary]
)
on [primary];
定义以下索引:
create nonclustered index ix_hugetable on dbo.hugetable (
fk asc, added asc, id asc
) include(value) 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];
该ID字段是多余的,从以前的DBA谁坚持认为,制造品的所有表无处不应该有一个GUID,没有例外。