标志与表拆分


10

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

我考虑两个设计选项:

  • 一点标志
  • 单独的“未批准”项目表-批准项目后,将其移至“常规”表(项目ID的更新不是问题)

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

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


1
请记住,您可以使用过滤索引来帮助加快对批准记录的访问。brentozar.com/archive/2013/11/…–
mendosi

不幸的是,过滤后的索引未在参数化查询中使用。
迪马

@Dima并非完全正确。如果过滤后的索引具有say,WHERE status='A'而查询具有WHERE status = 'A' AND (... other columns and parameters here...),则该索引可能仍会使用。
ypercubeᵀᴹ

Answers:


6

分区视图可以同时使用。

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

好处是
a)索引较浅。但是,对索引扇出进行数学运算。以这种比例在状态值之间进行拆分时,索引在拆分表上的深度可能与在合并表上的深度相同。
b)无需更改应用程序代码。数据继续显示为连续的整体。
c)可以通过添加新的具有约束的基本表并重新创建视图来包括将来的新状态值。

代价就是所有数据移动。每个状态更新将写入两个页面和相关的索引。有很多IO需要处理。这么多的运动也会导致碎片。


5

一个项目表,该项目表(可能)包含数千万条记录。

考虑到SQL Server可以有效处理的内容,实际上并没有那么多。当然,我还记得我以前的工作之一,其中最大的表之一(单实例系统)有200万行,这是我处理过的最多表。然后下一个作业有17个Production实例,其中某些表包含亿万行,并且所有这些都被汇总到一个数据仓库中,而事实表则具有超过10亿行。不要误会我的意思,我并不是在嘲笑数千万行,我只是在强调,借助良好的数据模型和适当的索引编制(以及索引维护),SQL Server可以处理很多事情

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

嗯 听起来不对。“批准”条目的比率将是获得新条目的比率的一半?每2个新条目中,只有1个会被“批准”?在您的200万行的示例中,“批准”和“未批准”分别为100万行,几年后又有了1000万个条目,您期望“批准”和“未批准”分别为600万行吗?还是100万个“未批准”会保持一定的不变性,以至于有1000万个新条目,将有1100万个“已批准”,还有100万个“未批准”?

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

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

因此,让我们看一下选择:

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

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

两个单独的表(一个表为“已批准”,一个表为“未批准”)

  • 查询每种状态的速度略快
  • 随时间变化的灵活性较弱/难以合并诸如第三种状态的更改(例如“已存档”);新状态很可能需要另一个表,并且肯定需要新的和更新的代码。
  • 将记录从“未批准”表移至“已批准”表的工作量更大(例如代码,测试等),还有更多的出错空间
  • 更复杂=长期的维护成本更高,新员工需要更长的培训时间
  • (可能)由于删除了一张表并插入了一张表,因此对事务日志的影响更大
  • 没有必要对“担忧的物品的ID更新 ”:未批准表有ID列,它是一IDENTITY列,并批准表有ID列,它是不是一个IDENTITY(因为不需要那里)。因此,ID值随着记录在表之间移动而保持一致。

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


它是一个数据快速移动的表:经常填充很多新行,经常删除行。我试图删除所有细节(例如业务决策,客户编码等),以仅关注单个主题。基本上,我们有带有标志的旧设计表。而且我100%知道将标志设置为1的行从未在任何其他表中使用。因此,我认为它们仅在此处发生,并且可能会移动到单独的表中。几乎在对数据库的每个查询中都扫描该表。因此,降低其“重量”可能会减少CPU / IO操作。
迪马

3
拆分表的另一个优点:您可以拥有仅引用“已批准”表的FK。
ypercubeᵀᴹ

单个实体的拆分表的另一个问题是约束完整性。来自其他表的引用将无法与记录一起移动。这将需要编写代码来解决这些问题,例如拆分表的镜像参考表->非常麻烦
user1567453
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.