在日期时间字段上涉及 CAST 或 TRUNCATE 或 DATEPART 操作的每个选项都有相同的问题:查询必须扫描整个结果集(40k)才能找到不同的日期。各种实现之间的性能可能略有不同。
您真正需要的是有一个可以在眨眼间产生响应的索引。您可以拥有一个带有索引的持久计算列(需要更改表结构)或一个索引视图(需要企业版 QO 以考虑开箱即用的索引)。
持久计算列:
alter table foo add date_only as convert(char(8), [datetimecolumn], 112) persisted;
create index idx_foo_date_only on foo(date_only);
索引视图:
create view v_foo_with_date_only
with schemabinding as
select id
, convert(char(8), [datetimecolumn], 112) as date_only
from dbo.foo;
create unique clustered index idx_v_foo on v_foo_with_date_only(date_only, id);
更新
要完全消除扫描,可以使用 GROUP BY 欺骗索引视图,如下所示:
create view v_foo_with_date_only
with schemabinding as
select
convert(char(8), [d], 112) as date_only
, count_big(*) as [dummy]
from dbo.foo
group by convert(char(8), [d], 112)
create unique clustered index idx_v_foo on v_foo_with_date_only(date_only)
查询select distinct date_only from foo
将改为使用此索引视图。在技术上仍然是扫描,但在已经“不同”的索引上,因此只扫描所需的记录。我认为它是一种 hack,我不建议将它用于实时生产代码。
AFAIK SQL Server 不具备通过跳过重复扫描真实索引的能力,即。寻找顶部,然后寻找大于顶部,然后连续寻找大于最后发现的东西。