【问题标题】:SQL Server Indexes of DateTime Parts such as YEAR, MONTH日期时间部分的 SQL Server 索引,例如 YEAR、MONTH
【发布时间】:2012-08-31 11:04:11
【问题描述】:

是否可以在DateTime 部分(例如DATEPART(YEAR, bp.[CreatedOn]) 和DATEPART(MONTH, bp.[CreatedOn]))上建立索引?例如,我有以下 T-SQL 查询:

DECLARE @year AS INT = 2012;
DECLARE @month AS INT = 8;

SELECT bp.Title, bp.CreatedOn FROM BlogPosts bp
WHERE (DATEPART(YEAR, bp.[CreatedOn]) = @year) AND (DATEPART(MONTH, bp.[CreatedOn]) = @month)
ORDER BY bp.CreatedOn;

这是我的执行计划:https://gist.github.com/3551450

目前记录不多,所以性能方面不是大问题,但记录会随着时间的推移而增长。

【问题讨论】:

    标签: sql-server sql-server-2008 tsql indexing


    【解决方案1】:

    您最好使用日期时间字段构建标准:

    declare @startMonth datetime = '20120801'
    
    SELECT bp.Title, bp.CreatedOn 
      FROM BlogPosts bp
     WHERE bp.[CreatedOn] >= @startMonth
       AND bp.[CreatedOn] < dateadd (month, 1, @startMonth)
    ORDER BY bp.CreatedOn;
    

    这样查询执行器将能够在 CreatedOn 上使用索引。

    【讨论】:

    • 嗯,好主意!谢谢。那么,不能在 DateTime 部分上创建索引吗?
    • @tugberk 如果您使用持久计算列并对其进行索引,它可能会。
    • -1。这必须在所有记录上运行dateadd,因此必须加载所有记录(全表扫描)- 性能非常差。我打赌你会在执行计划中看到这一点。
    • @Aliostad 如果 createdOn 上有索引,这不会导致全表扫描。即使没有,它的性能也会比 (DATEPART(YEAR, bp.[CreatedOn]) = @year)....
    • +1 这只是一个简单的索引范围搜索。看不到添加单独的年份和月份列将如何提高性能。如果有的话,它会因为每页的行数减少而影响性能。
    【解决方案2】:

    是的,是否可以将索引放在年份和月份上。这是一个例子:

    create table testt(d datetime)
    alter table testt add year as year(d) PERSISTED -- after marc_s advise. Thx
    alter table testt add month as month(d) PERSISTED --
    
    create index idx_year on testt(year)
    create index idx_month on testt(month)
    

    但是我总是会使用 Nikola 解决方案的变体,所以 +1 给 Nikola。

    这是您可以将月份和年份重写为日期的方法:

    DECLARE @year AS INT = 2012;
    DECLARE @month AS INT = 8;
    DECLARE @from DATE = dateadd(month, (@year-1900)*12 + @month - 1, 0)
    

    【讨论】:

    • 甚至更好 - 使这些计算列 持久化:ALTER TABLE dbo.TestT ADD MyMonth AS MONTH(d) PERSISTED - 这样它们的值就不会在每次被访问时重新计算......
    【解决方案3】:

    我建议您将日期部分存储在不同的字段中。显然,这是您的域中存在的要求,因为它需要成为您的模型的一部分。

    你失去的是你必须为你加载的每个模型构建日期时间,或者你设置值,但这将是几个 CPU 周期。

    【讨论】:

    • 这只是一个简单的查询,用于恢复给定月份创建的所有项目。无需为此存储分解的日期。
    • @MartinSmith 这个是的。但正如我所说,将会有(我认为)更多与日期相关的东西,所以我建议这样做。
    • 好吧,这是可能的,但是(我猜)你需要创建一个触发器来保持年份和月份列同步,以防CreatedOn 发生更改(极不可能可以更改)。
    • 触发器??真的??不碰魔鬼的工具。
    • 将 DateTime 分解为单个组件进行存储的一个缺点是,您必须重新发明一些使用 DateTime 免费获得的验证。例如,如果您分别存储月、日和年,则可以插入无效日期,例如 2012 年 1 月 32 日。当然,您可以添加范围检查约束,但是对于闰年(例如,2011 年 2 月 29 日),这会变得很棘手。
    猜你喜欢
    • 2010-12-27
    • 1970-01-01
    • 1970-01-01
    • 2021-10-05
    • 2010-12-19
    • 2021-01-15
    • 2010-09-07
    • 2010-09-05
    相关资源
    最近更新 更多