我记得在某一点上读取索引具有低基数(少量不同值)的字段并不值得做.我承认我对索引如何理解为什么不够了解.
那么,如果我有一个包含1亿行的表,并且我选择位字段为1的记录呢?让我们说在任何时间点,只有少数记录位字段为1(而不是0).是否值得索引该位字段?为什么?
当然我可以测试它并检查执行计划,我会这样做,但我也很好奇它背后的理论.什么时候基数很重要,什么时候不重要?
考虑SQL中的索引是什么 - 而索引实际上是指向其他内存块(即指向行的指针)的一块内存.索引被分成页面,以便可以根据使用情况从内存中加载和卸载索引的某些部分.
当您要求一组行时,SQL使用索引比表扫描更快地查找行(查看每一行).
SQL具有聚簇索引和非聚簇索引.我对聚簇索引的理解是它们将类似的索引值分组到同一页面中.这样,当您要求所有与索引值匹配的行时,SQL可以从内存的聚簇页面返回这些行.这就是为什么尝试集群索引GUID列是一个坏主意 - 您不要尝试集群随机值.
索引整数列时,SQL的索引包含每个索引值的一组行.如果你的范围是1到10,那么你将有10个索引指针.根据有多少行,可以不同地分页.如果您的查询查找匹配"1"的索引,然后查找Name包含"Fred"的位置(假设Name列未编入索引),则SQL会非常快速地获取与"1"匹配的行集,然后通过表扫描查找其余行.
那么SQL真正在做的是尝试减少它必须迭代的工作集(行数).
索引位字段(或某个窄范围)时,只会将工作集减少与该值匹配的行数.如果你有少量的行匹配它会减少你的工作集很多.对于50/50分布的大量行,与保持索引最新相比,它可能会为您带来非常小的性能提升.
每个人都说要测试的原因是因为SQL包含一个非常聪明且复杂的优化器,如果它决定表扫描更快,或者可能使用排序,或者可能组织内存页面,它可能会忽略索引,但它很喜欢.
我只是通过另一个问题来看待这个问题.假设您的声明只有少数记录假定值为1(并且那些是您感兴趣的那些),那么过滤后的索引可能是一个不错的选择.就像是:
create index [IX_foobar] on dbo.Foobar (FooID) where yourBitColumn = 1
这将创建一个小得多的索引,优化器足够聪明,当它是查询中的谓词时使用.
1亿个记录,只有少数记录的位字段设置为1?是的,我认为索引位字段肯定会加快查询bit = 1记录.您应该从索引获取对数搜索时间,然后只触摸bit = 1记录的几个页面.否则,您必须触摸1亿记录表的所有页面.
然后,我绝对不是数据库专家,可能会遗漏一些重要的东西.
如果您的分布是众所周知且不平衡的,例如99%的行是bit = 1而1%是bit = 0,那么当您使用bit = 1执行WHERE子句时,全表扫描将与索引扫描.如果你想快速查询bit = 0,我知道的最好方法是创建一个过滤索引,添加一个子句WHERE bit = 0.这样,该索引只存储1%的行.然后执行WHERE位= 0将简单地让查询优化器选择该索引,并且其中的所有行都将为bit = 0.还有一个好处是比较位上的完整索引需要非常少量的磁盘空间.
虽然我不认为我会单独索引JUST一个列,但将列列作为复合索引的一部分是很常见的.
一个简单的例子是当您的应用程序几乎总是在寻找活跃客户时,ACTIVE,LASTNAME而不是lastname上的索引.
如果您还没有阅读,Jason Massie最近写了一篇文章,讨论了这个话题.
http://statisticsio.com/Home/tabid/36/articleType/ArticleView/articleId/302/Never-Index-a-BIT.aspx
编辑:新文章位置 - http://sqlserverpedia.com/blog/sql-server-bloggers/never-index-a-bit
以前"新"文章位置的Wayback机器:http://web.archive.org/web/20120201122503/http : //sqlserverpedia.com/blog/sql-server-bloggers/never-index-a-bit/
新的SQL Server Pedia位置是Toadworld,其中有一篇来自Kenneth Fisher的新文章讨论了这个主题:
http://www.toadworld.com/platforms/sql-server/b/weblog/archive/2014/02/17/dba-myths-an-index-on-a-bit-column-will-never-be- used.aspx