我们目前有一个场景,其中一个表实际上有几个(10到15)布尔标志(不是可空的bit
字段)。不幸的是,在逻辑层面上实际上不太可能简化这一点,因为布尔值的任何组合都是允许的。
有问题的表是一个事务表,最终可能有数千万行,插入和选择性能都非常关键。虽然我们目前还不太确定数据的分布,但所有标志的组合应提供相对良好的基数,即使其成为SQL Server使用的“有价值”索引。
典型的选择查询方案可能是仅基于3或4个标志选择记录,例如WHERE FLAG3=1 AND FLAG7=0 AND FLAG9=1
。为这些选择查询使用的所有标志组合创建单独的索引是不切实际的,因为它们中有很多。
鉴于这种情况,有效索引这些字段的推荐方法是什么?该表是新的,因此目前还没有现成的数据需要担心,我们在实际执行表时有相当大的灵活性。
目前我们正在考虑两个主要选项:
int
字段)。我担心的是,鉴于仅包含一些字段的典型用法,此方法将跳过索引并采用表扫描。让我们称之为选项A (看过一些回复后,似乎这种方法效果不好,因为索引中字段的顺序会有所不同,因此无法有效地索引所有领域)。目前,我们非常倾向于选项B 。为了完整起见,这将在SQL Server 2008上运行。
非常感谢任何建议。
修改:拼写,清晰度,查询示例,选项B 的其他信息。
答案 0 :(得分:6)
单个BIT
列通常没有足够的选择性,甚至不能考虑在索引中使用。因此,单个BIT列上的索引确实没有意义 - 平均而言,您总是必须搜索表中大约一半的条目(50%选择性),因此SQL Server查询优化器将改为使用表扫描
如果您在所有15个bit
列上创建单个索引,那么您就没有这个问题 - 因为您有15个是/否选项,您的索引将变得非常有选择性。
麻烦的是:位列的序列很重要。如果您的SQL语句至少使用最左侧BIT
列的1-n,那么您的索引将仅。
所以如果您的索引在
Col1,Col2,Col3,....,Col14,Col15
然后它可能用于使用
的查询Col1
Col1
和Col2
Col1
以及Col2
和Col3
.... 等等。但无法用于指定Col6,Col9
和Col14
的查询。
因此,我并不认为您的BIT
列集合中的索引真的很有意义。
这15个BIT
列是您用于查询的唯一列吗?如果没有,我会尝试将您最常用的BIT列与其他列结合使用,例如:有Name
和Col7
之类的索引(那么你的BIT
列可以为另一个索引添加一些额外的选择性)
答案 1 :(得分:3)
虽然可能有办法解决现有表架构的索引问题,但我会将其减少为规范化问题:
例如,我强烈建议您创建一系列新表:
CREATE TABLE Flags (id int IDENTITY(1,1), Name varchar(256))
(如果你想手动控制id,你不必将id作为身份种子列 - 例如2,4,8,16,32,64,128作为二进制标志。)CREATE TABLE DataFlags_Link (id int IDENTITY(1,1), MyFlagId int, DataId int)
然后,您可以在DataFlags_Link
表上创建索引并编写如下的查询:
SELECT Data.*
FROM Data
INNER JOIN DataFlags_Link ON Data.id = DataFlags_Link.DataId
WHERE DataFlags_Link.MyFlagId IN (4,7,2,8)
至于性能,这就是良好的DBA维护所在。您需要在表上适当地设置INDEX填充因子和填充,并按计划运行常规索引碎片整理或重建索引。
性能和维护与数据库齐头并进。你不能没有另一个。
答案 2 :(得分:1)
虽然我认为Neil Fenwick的答案可能是正确的,但我认为真正的答案是尝试不同的选项,看看哪一个足够快。
选项1可能是最直接的解决方案,因此可能是最易维护的解决方案 - 而且它可能足够快。
我将使用“选项1”架构构建原型数据库,并使用http://www.red-gate.com/products/sql-development/sql-data-generator/或http://sourceforge.net/projects/dbmonster/之类的内容创建两倍于您预期需要的数据,然后构建查询你期望需要。同意可接受的响应时间,并且如果超过响应时间,则只考虑“更快”的模式(并且您不能在问题上抛出硬件)。
Neil的解决方案可能与“选项1”一样明显且可维护 - 并且应该很容易编制索引。但是,我仍然通过创建原型模式并生成大量测试数据来测试它......