我已经读过布尔列如何不像搜索索引那样。 但我的问题是..如果聚集索引,会影响记录的物理排列 不能用它来放置一种类型的记录(在同一页面中),以便这些页面被加载到内存中的机会较少。 我将尝试更好地解释:对于表
[BookPages]
ID(int)
Deleted(Boolean)
Text(Varchar)
如果聚集索引位于ID
列,则示例数据为
1, true, 'the quick..'
2, false, 'hello w..'
3, true, 'stack m..'
4, false, 'just thin...'
这意味着删除/活动记录为交错,因此如果我们搜索记录2
SELECT [Text] FROM [BookPages] WHERE [Deleted] = false AND [ID] = 2
“leaf”数据页面可能以行(1,2)结束,这意味着我们正在加载到内存中,带有已删除字段的记录,我们将永远不会感兴趣。
但如果索引位于Deleted,ID
列中,则数据现在为
2, false, 'hello w..'
4, false, 'just thin...'
1, true, 'the quick..'
3, true, 'stack m..'
现在,当我们在SQL加载页面时只定位活动记录时,我们将只有活动记录的页面。
因此,对于历史悠久且删除记录很多的数据库,我们可以在我们想要的记录上获得更好的位置,并帮助IO ..
在数千页上,我们可以确保它们中的大部分永远不会被加载到内存中,并且数据将始终只保留在磁盘上。
这个推理是否正确?这可能会影响(改善)大型数据库的整体性能吗?
答案 0 :(得分:3)
是的,这种推理是正确的。实际上,您可以将数据集划分为两个区域,一个是热区域,另一个是冷区域。使用一点只是这种技术的一个特例。您还可以使用日期列和集群(当然,这是否可行取决于架构和数据)。
分区具有类似的效果。选择聚类键的重量更轻,但同样好。
通常,对自动递增数字进行聚类也具有良好的局部性,因为IDENTITY
值与年龄和年龄相关,与使用频率相关。
相同的优化不直接适用于非聚簇索引。您也可以为它们使用布尔前缀,但是您需要以可搜索的形式提供它:
WHERE SomeNCIndexCol = '1234' AND Deleted IN (0, 1)
SQL Server不够智能,无法自行解决这个问题。它不能像Oracle那样“跳过”第一个索引级别。所以我们必须手动提供搜索键。 (连接项目:https://connect.microsoft.com/SQLServer/feedback/details/695044)
另一个问题是写性能。将行标记为已删除(SET Deleted = 1
)现在需要CI的物理删除+插入对以及每个NCI的一对。大多数ORM不支持主键更改,因此您可能不应将此群集键设置为主键。
作为旁注,在位列上创建索引也有其他用例。如果99%的值为零或一个,您绝对可以使用索引执行搜索和键查找。您也可以使用这样的索引进行计数(或对位列进行分组)。
答案 1 :(得分:0)
在具有两个或几个可能值的列上创建索引实际上会适得其反。对布尔列进行聚类也可能不明智,因为您可能希望将其保存到经常查询的其他列。示例,CustomerName。如果您的数据库服务器支持碎片,您可以在逻辑上将最少访问的行放入具有错误值的已删除列的单独表中。请参阅以下相关question/answers。