我有一个表A,除了一些其他列之外,它还有一个startDate和一个结束dateDate作为2个datetime列。我有另一个表B,它有一个日期时间列调用它的日期列。这是在SQL Server 2005中。
这里的问题是:如何最好地设置索引等以获得以下内容:
select ....
from A , B
where A.startDate >= B.dates
and A.endDate < B.dates
两个表都有几千条记录。
答案 0 :(得分:7)
<强>更新强>
在我的博客中查看此文章,了解使用计算列的查询的高效索引策略:
主要思想是我们只为您的范围计算舍入length
和startDate
,然后使用相等条件(适用于B-Tree
索引)搜索它们
在MySQL
和SQL Server 2008
中,您可以使用SPATIAL
个索引(R-Tree
)。
它们特别适合“选择记录范围内给定点的所有记录”这样的条件,这就是你的情况。
您将start_date
和end_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)
如果您需要优化尝试在查询分析器中运行此查询。