SQL Server中多个位字段的索引

SQL Server中多个位字段的索引,sql,sql-server,sql-server-2008,indexing,Sql,Sql Server,Sql Server 2008,Indexing,我们目前有一个场景,其中一个表有效地具有多个(10到15个)布尔标志(不可为空bit字段)。不幸的是,在逻辑层面上不可能将其简化得太多,因为布尔值的任何组合都是允许的 所讨论的表是一个事务性表,它可能最终拥有数千万行,而insert和select性能都相当关键。虽然我们目前还不太确定数据的分布情况,但所有标志的组合应该提供相对良好的基数,即使其成为SQL Server“值得”使用的索引 典型的选择查询场景可能是仅基于3或4个标志选择记录,例如,,其中FLAG3=1、FLAG7=0和FLAG9=1

我们目前有一个场景,其中一个表有效地具有多个(10到15个)布尔标志(不可为空
bit
字段)。不幸的是,在逻辑层面上不可能将其简化得太多,因为布尔值的任何组合都是允许的

所讨论的表是一个事务性表,它可能最终拥有数千万行,而insert和select性能都相当关键。虽然我们目前还不太确定数据的分布情况,但所有标志的组合应该提供相对良好的基数,即使其成为SQL Server“值得”使用的索引

典型的选择查询场景可能是仅基于3或4个标志选择记录,例如,
,其中FLAG3=1、FLAG7=0和FLAG9=1
。为这些select查询所使用的所有标志组合创建单独的索引是不实际的,因为其中会有很多

在这种情况下,建议采用什么方法对这些字段进行有效索引?该表是新的,因此还没有需要担心的现有数据,我们在实际实现该表时有相当大的灵活性

我们目前正在考虑两个主要方案:

  • 创建一个包含所有位字段的索引(这可能包括1或2个始终使用的其他
    int
    字段)。我担心的是,鉴于只包含几个字段的典型用法,这种方法将跳过索引,而求助于表扫描。让我们把这个选项称为A(阅读了一些回复后,这种方法似乎不太管用,因为索引中字段的顺序会产生影响,使得无法对所有字段进行有效索引)
  • 有效地执行我认为SQLServer在内部所做的操作,并使用二进制运算符(以及将数字加和或加在一起:1、2、4、8等)将位字段编码为单个整型字段。我关心的是,我们需要做一些计算来查询这个编码字段,这将再次跳过索引。维护和此解决方案的复杂性也是一个问题。让我们称之为选项B附加信息:这种方法的理由是,我们可以有一个相对简单和简短的索引,其中包括表和此字段中的一个或两个其他字段。其他字段将缩小需要计算的记录数,并且由于编码字段将包含我们的所有位字段,SQL Server将能够使用直接从索引(即索引扫描)检索的数据而不是表(即表扫描)执行计算
目前,我们严重倾向于选项B。为了完整起见,这将在SQLServer2008上运行

如有任何建议,将不胜感激


编辑:拼写、清晰度、查询示例、关于选项B的附加信息

单个
列的选择性通常不足以考虑在索引中使用。因此,单位列上的索引实际上没有意义——平均而言,您总是需要搜索表中大约一半的条目(50%的选择性),因此SQL Server查询优化器将使用表扫描

如果您在所有15个
bit
列上创建一个索引,那么您就不会有这个问题-因为您有15个yes/no选项,您的索引将变得非常有选择性

问题是:位列的序列很重要。如果您的SQL语句使用了最左边的
列中至少1-n个,那么您的索引将永远不会被考虑

所以如果你的索引是开着的

Col1,Col2,Col3,....,Col14,Col15
然后,它可能用于使用

  • Col1
  • Col1
    Col2
  • Col1
    Col2
    Col3
    ....
等等。但是它不能用于指定
Col6、Col9
Col14
的查询

正因为如此,我认为在你的
BIT
列集合上建立一个索引并没有多大意义


这15个
BIT
列是用于查询的唯一列吗?如果没有,我会尝试将您用于选择的那些最常用的位列与其他列组合,例如,在
Name
Col7
上有一个索引或其他什么(那么您的
BIT
列可以为另一个索引添加一些额外的选择性)

虽然可能有一些方法可以解决针对现有表架构的索引问题,但我会将其简化为规范化问题:

e、 g我强烈建议创建一系列新表:

  • 此位标志名称的查找表。e、 g.
    创建表标志(id int-IDENTITY(1,1),Name-varchar(256))
    (如果您想手动控制id,则不必将id设为标识种子列,例如2,4,8,16,32,64128作为二进制标志。)
  • 创建包含原始数据表和新链接表id的新链接表,例如
    Create table DataFlags\u link(id int IDENTITY(1,1),MyFlagId int,DataId int)
  • 然后,您可以在
    DataFlags\u链接上创建一个索引,并编写如下查询:

    SELECT Data.*
    FROM Data
    INNER JOIN DataFlags_Link ON Data.id = DataFlags_Link.DataId
    WHERE DataFlags_Link.MyFlagId IN (4,7,2,8)
    
    至于性能,这就是好的DBA维护的关键所在。您需要在表上适当地设置索引填充因子和填充,并运行定期索引碎片整理或按计划重建索引


    性能和维护与数据库密切相关。你不能没有另一个。虽然我认为尼尔·芬威克的答案可能是正确的,但我认为真正的答案是尝试不同的方法