通常我们会遇到这样的情况,一张表中包含上百万条的数据,但是每次我们只查询一小部分的数据。
比如一列只有少部分NULL值,每次我们都需要将Null值找出来进行处理。或者我们有状态标志位,需要取Flag对数据处理。 由于数据大部分是重复的,所以对于整个列做索引代价是非常大的,而且对查询性能提升可能不大。
庆幸的是微软提供了Filtered index。Filtered index引使用筛选谓词对表中的部分行进行索引,与全表索引相比,设计良好的筛选索引可以提高查询性能、减少索引维护开销并可降低索引存储开销。
下面是我做的一个测试:
CREATE TABLE [dbo].[test](
[test1] [varchar](100) NULL,
[test2] [varchar](100) NULL,
[test3] [varchar](100) NULL,
[test4] [varchar](100) NULL,
[test5] [varchar](100) NULL,
[flag] [char](1) NULL
) ON [PRIMARY]
flag列只有N和Y两个值。然后插入100W数据,Flag为N,插入5000条Flag为Y,然后对表进行查询:
select flag from test where flag ='Y'---用了7秒钟返回数据
查看执行计划提示缺失索引,建议的创建脚本如下:
CREATE NONCLUSTERED INDEX [ix_filter_flag]
ON [dbo].[test] ([flag])
因为我们只针对于Flag为Y的数据查询,如果使用建议脚本创建索引对性能不会有大的提升而且会增加数据库的负担。 所以我选择用Flitered index:
CREATE NONCLUSTERED INDEX [ix_filter_flag]
ON [dbo].[test] ([flag])
WHERE flag='Y' ;
创建完成后运行上面的语句,发现使用了Index seek,时间不超过一秒中就返回了所有结果。
但是如果想查询Flag为N的,仍然是Table Scan:
当然我们可能还需要查询其他的字段,创建索引的时候还可以配合Include使用。
使用Filtered index还有一些限制,更多信息可以参考MSDN:http://technet.microsoft.com/en-us/library/cc280372.aspx