给定日期范围的此查询的最快方式(最佳策略是什么)

时间:2009-08-05 11:52:39

标签: sql-server sql-server-2005 tsql

我有一个表A,除了一些其他列之外,它还有一个startDate和一个结束dateDate作为2个datetime列。我有另一个表B,它有一个日期时间列调用它的日期列。这是在SQL Server 2005中。

这里的问题是:如何最好地设置索引等以获得以下内容:

select ....
 from A , B
where A.startDate >= B.dates
  and A.endDate < B.dates

两个表都有几千条记录。

10 个答案:

答案 0 :(得分:7)

<强>更新

在我的博客中查看此文章,了解使用计算列的查询的高效索引策略:

主要思想是我们只为您的范围计算舍入lengthstartDate,然后使用相等条件(适用于B-Tree索引)搜索它们


MySQLSQL Server 2008中,您可以使用SPATIAL个索引(R-Tree)。

它们特别适合“选择记录范围内给定点的所有记录”这样的条件,这就是你的情况。

您将start_dateend_date存储为LineString的开头和结尾(将其转换为另一个数值的UNIX个时间戳),将其编入索引SPATIAL使用LineString索引并搜索其最小边界框({​​{1}})包含相关日期值的所有此类MBR

请在我的博客中查看此条目,了解如何在MBRContains中执行此操作:

以及MySQL的简要性能概述:

可以应用相同的解决方案来搜索存储在数据库中的网络范围的给定SQL Server

此任务与您查询一起,是此类情况的另一个常用示例。

如果范围可以重叠,则普通IP索引不好。

如果他们不能(而且你知道),你可以使用B-Tree提出的出色解决方案

另请注意,此查询性能完全取决于您的数据分发。

如果@AlexKuznetsov中有大量记录,而B中的记录很少,则可以在A上构建索引并让B.dates放在TS/CIS上去吧。

此查询将始终读取A中的所有行,并在嵌套循环中使用A上的Index Seek

如果您的数据以其他方式分发,我。即B.dates中有很多行但A中很少,而且范围通常很短,那么您可以稍微重新设计一下表格:

B

,在A start_date interval_length

上创建综合索引

并使用此查询:

A (interval_length, start_date)

答案 1 :(得分:3)

答案 2 :(得分:2)

我曾在两家公司工作过(包括时间和考勤管理系统),这些公司有很多次使用startDate和endDate列。根据我的经验,没有好的索引始终日期范围一起使用。

尝试索引(如startDate,-endDate)和(-endDate,startDate)以查看它们是否有用,很大程度上取决于表格中的数据。例如,如果您在查找日期之前往往有很多带有endDate的旧行,那么强制Sql使用基于(endDate,startDate)的索引可能有所帮助。

另外尝试使用覆盖“where”语句中所有列的索引,因此在找出要返回的行之前,sql不需要读取主表。

可能必须使用索引提示,因为查询处理器不太可能对数据有足够的了解以便很好地选择索引 - 这是极少数我不得不考虑索引提示的情况。

扩展数据,因此您需要一个包含(日期,划船)的表格,其中包含日期范围内每个日期的行可能。但是,保持“索引”表更新是一件痛苦的事。

如果您知道某些日期范围不重叠,请查看Using CROSS APPLY to optimize joins on BETWEEN conditions(例如,员工的病情记录可能不允许重叠)

如果你只有几千条记录,那么在一天结束时,全表扫描也不错。

Quassnoi subjects using SPATIAL indexes,我没有以这种方式“滥用”空间索引的经验,但我认为值得尝试。但是,如果您需要支持多个数据库供应商,请务必小心,因为空间索引相当新。此外,您可能仍需要报告工具等的日期列。

(迟早需要能够找到与日期范围重叠的所有行,然后变得更难以获得返回良好结果的索引。)

答案 3 :(得分:0)

每个版本的sql server 2000,2005,2008都有一个名为DataBase tuning advisor的程序,当你运行一些查询它告诉你需要添加哪些索引来更快地获取查询 最好的祝福, 约尔丹

答案 4 :(得分:0)

你需要3个索引A.startDate,B.dates和A.endDate,可能是索引(A.endDate + A.startDate)也不错。 我没有关于这些表的其他列和目的的详细信息,但查看使用聚簇索引的可能性。

无论如何使用“执行计划”选项在所有这些变体之间做出决定,因为我的建议过于笼统

答案 5 :(得分:0)

以下脚本将列出可能缺少的索引(您可以通过t.name过滤语句)。

SELECT     t.name AS 'affected_table',
           'Create NonClustered Index IX_' + t.name + '_missing_' + CAST(ddmid.index_handle AS VARCHAR(10)) + ' On ' + ddmid.STATEMENT + ' (' + ISNULL(ddmid.equality_columns, '') +
           CASE
                      WHEN ddmid.equality_columns IS NOT NULL
                             AND ddmid.inequality_columns IS NOT NULL
                      THEN ','
                      ELSE ''
           END + ISNULL(ddmid.inequality_columns, '') + ')' + ISNULL(' Include (' + ddmid.included_columns + ');', ';') AS sql_statement,
           ddmigs.user_seeks,
           ddmigs.user_scans,
           CAST((ddmigs.user_seeks + ddmigs.user_scans) * ddmigs.avg_user_impact AS INT) AS 'est_impact',
           ddmigs.last_user_seek
FROM       sys.dm_db_missing_index_groups      AS ddmig
INNER JOIN sys.dm_db_missing_index_group_stats AS ddmigs
ON         ddmigs.group_handle = ddmig.index_group_handle
INNER JOIN sys.dm_db_missing_index_details AS ddmid
ON         ddmig.index_handle = ddmid.index_handle
INNER JOIN sys.tables AS t
ON         ddmid.OBJECT_ID = t.OBJECT_ID
WHERE      ddmid.database_id = DB_ID()
       AND CAST((ddmigs.user_seeks + ddmigs.user_scans) * ddmigs.avg_user_impact AS INT) > 100
ORDER BY   CAST((ddmigs.user_seeks + ddmigs.user_scans) * ddmigs.avg_user_impact AS INT) DESC;

答案 6 :(得分:0)

需要更多信息。表中有多少列?具有大量查询的现有表是否已经针对它们或所有新表?您认为哪种性能问题导致您提出问题?

我假设所有三列都不是NULL(不仅仅是查询语法,而是索引的有用性)。

我将从A.startDate + A.endDate上的复合索引和B.dates上的另一个索引开始(但这可能不需要)。除非这些日期是表的主要目的,否则我将避免在这些列上创建聚簇索引。如果这些表是包含针对它们运行的​​其他查询的现有表,则这是双重的。可以编写先前的查询,期望现有的聚簇索引。

答案 7 :(得分:0)

我会选择

CREATE CLUSTERED INDEX IX_DateRange ON dbo.A
    (
    StartDate,
    EndDate DESC
    ) 
GO

答案 8 :(得分:-1)

我只想在B.dates上添加一个聚簇索引。如果你在startDate和endDate上添加索引,它将不会购买任何东西,因为你无论如何都会在A上获得索引扫描。 B上的聚簇索引至少可以获得B中的索引搜索。表扫描和索引扫描是一回事,因此添加索引以使表扫描从执行计划中删除是没有意义的:)

我会通过几种方式嘲笑它,或者看看你是否可以重做你的查询,不需要在A上进行表扫描,我猜这是不可能的。

答案 9 :(得分:-5)

如果您需要优化尝试在查询分析器中运行此查询。