标志与表拆分

Dim*_*ima 10 database-design sql-server

我正在设计一个将(可能)包含数千万条记录的项目表。某些项目在管理员“批准”之前将无法使用。“使用”是指这些项目在“批准”之前不会在任何其他表格中引用。在任何给定时间,多达 50% 的商品都可能“未获批准”。记录可能会被“批准”,但反之则不然。

我考虑了两种设计方案:

  • 一点旗
  • 一个单独的“未批准”项目表 - 当项目被批准时,它被移到“常规”表(项目 ID 的更新不是问题)

我认为第二种选择要好得多。位标志每行只占用一个字节,所以这不是问题。但是,如果我们在同一个表中有 100 万条已批准的记录和 100 万条未批准的记录 - 扫描时间会增加对已批准记录的操作。

问题是:我应该考虑第一个(位标志)选项吗?它在描述的情况下有什么好处吗?

Sol*_*zky 7

将(可能)包含数千万条记录的项目表。

考虑到 SQL Server 可以有效处理的内容,这实际上并没有那么多。当然,我记得我早期的工作之一,其中一个最大的表(单实例系统)有 200 万行,这是我处理过的最多的表。然后下一个作业有 17 个生产实例,其中一些表有数亿行,所有这些都被聚合到一个数据仓库中,其中包含多个具有超过 10 亿行的事实表。不要误会我的意思,我并不是嘲笑几千万行,我只是强调,有了良好的数据模型和适当的索引(和索引维护),SQL Server 可以处理很多.

在任何给定时间,多达 50% 的商品都可能“未获批准”。

唔。这听起来不对。“批准”条目的比率将是获得新条目的比率的一半?每 2 个新条目,只有 1 个会被“批准”?在您的 200 万行示例中,“已批准”和“未批准”各 100 万行,几年后又有 1000 万个条目,您预计“已批准”和“未批准”各有 600 万行?还是说100万个“未通过”会保持一定的水平,这样1000万个新条目,就会有1100万个“通过”,还有100万个“未通过”?

记录可能会被“批准”,但反之则不然。

今天确实如此,但事情会随着时间的推移而发生变化,因此企业总是有可能决定允许“未批准”或其他状态,例如“存档”等。

那么,让我们看看选择:

标志(甚至可能是TINYINT“状态”)

  • 查询每个状态稍慢
  • 随着时间的推移更加灵活/易于合并更改,例如仅具有新查找状态值的第三状态(例如“已存档”)。没有新表(必然),一些新代码,只有一些代码更新。
  • 较少的工作(即代码,测试等)和更少的空间误差更新单个TINYINT
  • 不那么复杂 = 随着时间的推移降低维护成本,缩短新员工的培训时间
  • (可能)更新一张表时对事务日志的影响较小
  • 只需要在两个表之间的“RecordStatus”和 FK 的查找表。

两张单独的表格(一张表“批准”,一张表“未批准”)

  • 查询各状态略快
  • 随着时间的推移不太灵活/更难合并第三种状态(例如“存档”)等更改;新状态很可能需要另一个表,并且肯定需要新的和更新的代码。
  • 更多的工作(即代码、测试等)和更多的错误空间将记录从“未批准”表移动到“已批准”表
  • 更复杂 = 随着时间的推移维护成本更高,新员工需要更长的培训时间才能弄清楚
  • (可能)删除一张表并插入一张表对事务日志的影响更大
  • 无需担心“更新项目 ID ”:未批准的表的 ID 列是一IDENTITY列,而批准的表的 ID 列不是一个IDENTITY(因为那里不需要)。因此,当记录在表之间移动时,ID 值保持一致。

就我个人而言,我倾向于从带有StatusID列的单个表开始。使用两个表似乎过于复杂,过早的优化。如果/当记录数达到数亿并且索引不提供任何性能提升,可以讨论这种类型的优化。

  • 拆分表的另一个优点:您可以拥有仅引用“已批准”表的 FK。 (3认同)

Mic*_*een 6

您可以同时使用分区视图

您为每个状态创建一个基础表,由约束强制执行,具有互斥的值。然后是将基础表联合在一起的视图。可以显式引用视图或每个基表。如果通过视图更新了一行的状态,DBMS 将从一个基表中删除它并将其插入到与新状态对应的表中。每个基表可以根据其使用模式独立索引。如果可以,优化器将解析对单个相应基表的索引引用。

好处是
a) 较浅的索引。但是,请对索引扇出进行数学计算。在这种规模和状态值之间的拆分下,拆分表上的索引可能与合并表上的深度相同。
b) 无需更改应用程序代码。数据继续作为一个连续的整体出现。
c) 可以通过添加带有约束的新基表并重新创建视图来包含未来的新状态值。

成本就是数据移动;为每个状态更新写入两个页面和相关索引。需要处理大量 IO。如此大的运动也会导致碎片化。