【发布时间】:2017-03-24 18:59:23
【问题描述】:
我需要存储简单的数据 - 假设我有一些产品的代码作为主键、一些属性和有效范围。所以数据可能如下所示:
Products
code value begin_date end_date
10905 13 2005-01-01 2016-12-31
10905 11 2017-01-01 null
这些范围没有重叠,所以在每个日期我都有一个独特产品及其属性的列表。所以为了方便使用,我创建了这个函数:
create function dbo.f_Products
(
@date date
)
returns table
as
return (
select
from dbo.Products as p
where
@date >= p.begin_date and
@date <= p.end_date
)
这就是我要使用它的方式:
select
*
from <some table with product codes> as t
left join dbo.f_Products(@date) as p on
p.code = t.product_code
这一切都很好,但我怎样才能让优化器知道这些行是独一无二的以有更好的执行计划?
我做了一些谷歌搜索,发现了几篇关于 DDL 的非常好的文章,它们可以防止在表中存储重叠范围:
- Self-maintaining, Contiguous Effective Dates in Temporal Tables
- Storing intervals of time with no overlaps
但即使我尝试了这些约束,我也看到优化器无法理解生成的记录集将返回唯一代码。
我想要的是某种方法,它给我的性能基本上与我在某个日期存储这些产品列表并使用date = @date 选择它一样。
我知道一些 RDMBS(如 PostgreSQL)对此有特殊的数据类型(Range Types)。但是 SQL Server 没有这样的东西。
我是否遗漏了什么或者没有办法在 SQL Server 中正确执行此操作?
【问题讨论】:
-
如果您关心性能,请不要使用 UDF。直接加入表即可。
-
@GordonLinoff 我不同意这一点,但这里不是这样,所以我们不要进行激烈的讨论
-
只是一个随机的想法:
begin_date上的索引,包含end_date,以及 UDF 中的SELECT TOP 1 ...?这会产生更好的执行计划吗? -
“这些范围不重叠”——除了它们是。你的第二行大概应该从
2017-01-01开始。 -
我认为您想以某种方式告诉优化器您的结果行是唯一的,因此您找错了树。您首先应该更关心的是让它有效地检索您感兴趣的行。 (不,截至 2018 年,SQL Server 仍然没有对范围的单独支持。)如果没有唯一性的“知识”,优化器将根据您要连接的另一个表的基数来决定连接类型,这应该没问题.
CREATE UNIQUE CLUSTERED INDEX IX_Products ON products([code], [begin_date], [end_date])应该是你所需要的一切......
标签: sql sql-server intervals sql-server-2016 date-range