表上的索引策略

时间:2009-01-07 16:30:27

标签: sql sql-server sql-server-2005 indexing

我有一个名为'EventTable'的SQL Server 2005表定义如下:

EventID,EventTypeCode,EventStatusCode,EventDate

目前该表在主键'EventID'上有一个聚簇索引,目前没有其他索引

EventTypeCode和EventStatusCode列是CHAR(3)(例如'NEW','SEN','SAL')并且是外键

Common Selects将是......

select * from EventTable Where EventDate = @dateparam;
select * from EventTable Where EventTypeCode = @eventtype;
select * from EventTable Where EventStatusCode = @statustype;

您将使用什么索引策略来处理上面的Select语句?

在3列上有覆盖(复合)索引是否更好?如果是这样,复合指数应该采用什么顺序?

或者在3列中的每一列上都有单独的索引?

该表将以每天约300个事件的速度增长..


执行诸如的查询也很常见

where EventDate between '2008-12-01' and '2008-12-31'
  and EventTypeCode = 'todo'

  • 该表更有可能以每天500-800 /条记录而不是300
  • 的速度增长
  • 在正常使用ASP.NET应用程序期间,初始问题中提到的查询将全天运行多次
  • NHibernate'HQL'用于执行此类查询
  • 没有初始加载的数据,该表现在只有大约10K记录,因为这是一个新的应用程序
  • ...我或多或少只是试图避免客户在几年内打电话给我们抱怨应用变得“慢”,因为这张桌子会被打得太厉害

4 个答案:

答案 0 :(得分:6)

策略1,提供可用于过滤的索引。表查找将获取剩余数据。这几乎使用空间和四倍写入IO成本加倍。

on EventTable(EventDate)
on EventTable(EventTypeCode)
on EventTable(EventStatusCode)

策略2,提供可用于过滤的覆盖索引。没有查找。 这使空间的使用翻了四倍,并且写入IO成本。

on EventTable(EventDate, EventId,
              EventTypeCode, EventStatusCode)
on EventTable(EventTypeCode, EventId,
              EventDate, EventStatusCode)
on EventTable(EventStatusCode, EventId,
              EventDate, EventTypeCode)

列覆盖索引(通常)中的列顺序重要的原因是数据依次按每列排序。也就是说:第2列打破了第1列。第3列打破第1列和第2列。

由于您没有对多列进行过滤的任何查询,因此对于第一列之后的列顺序没有任何意义(在您的情况下)。

如果您有查询,例如

where EventDate = @EventDate
  and EventTypeCode = @EventTypeCode

然后这个覆盖指数会很有用。 EventDate可能比EventTypeCode更具选择性,所以它首先出现。

on EventTable(EventDate, EventTypeCode,
              EventId, EventStatusCode)

进一步编辑: 如果您有查询,例如

where EventDate between '2008-12-01' and '2008-12-31'
  and EventTypeCode = 'todo'

然后这个指数最有效:

on EventTable(EventTypeCode, EventDate,
              EventId, EventStatusCode)

这将把所有'todo'事件放在一起,由他们的EventDate命令作为打破平局。 SQL Server只需找到第一个元素并读取,直到找到不符合条件的元素并停止。

如果EventDate是索引中的第一个,那么数据将按日期排序,然后每个日期都会将'todo'事件聚集在一起。 SQL Server会在12-01找到第一个待办事项,直到它找到一个不符合条件的元素...然后在12-02找到第一个待办事项,读到它不在todo的...然后找到。 ..出去31天。

您想要选择一个索引,将您想要的项目放在一起。


每天300条记录,您的餐桌将在50年内获得500万条记录。这不是那么大。这两种策略都可行。策略1可能足够快(错误在空间方面)。

答案 1 :(得分:1)

您对表格运行选择的频率如何?选择通常是正常处理的一部分还是更多的报告和/或维护和调试?

是否有初始数据加载?如果没有,表格大小非常小,很可能在未来几年保持这种状态。

虽然您提供了一些样本选择,但是您知道每种类型的选择的运行频率吗?

我可能只是将表保留原样并运行探查器以查看在生产中如何访问表。如果它将成为一个不断访问的表,并且可能成为不同函数的瓶颈,那么我会最好地猜测哪些列最常成为WHERE子句的一部分,并在其上放置一个索引。例如,如果有一个进程查看过去24小时内每隔10秒运行一次的所有事件,那么日期列上的索引可能会按顺序排列,我甚至会聚集在那个上而不是主键上。 / p>

答案 2 :(得分:0)

我会在每个外键上放一个索引(我通常索引大多数外键),然后在日期字段上放一个索引,具体取决于它在搜索中使用的频率。

答案 3 :(得分:0)

请查看有关SQL Server索引的这篇好文章:

http://www.mssqltips.com/tip.asp?tip=1206