Aid*_*das 12 sql database null database-design
我们有两个表:OriginalDocument和ProcessedDocument.在第一个中,我们放置了原始的,未处理的文档.在验证和处理(转换为我们的XML格式并解析)之后,它被放入ProcessedDocument表中.已处理的文档可能有效或无效.哪个更有意义:为有效和无效的文档设置两个不同的表,或者只有一个带有"有效"列的表?某些列(~5-7)与无效文档无关.存储无效和有效文档也会使文档表填充"NULL"列(如果文档无效,文档编号,接收器等信息可能是未知的).在做出这个决定时,我们还应该考虑和权衡什么呢?
无论文档是有效还是无效,它仍然是一个文档,因此它们使所有文档都在同一个表中.
但是,如果您的应用程序对无效文档的处理方式不同(几乎不会被查询,更新等),则拆分表格.将两种类型的文档放在同一个表中只会减慢您的查询速度而不会产生直接的好处.
我有一个文档表,其中有效和无效的文档保存在一起,但仅仅是因为应用程序将错误的文档重新呈现给用户并要求他们修复它.
对我来说听起来有一个位列是有道理的,因为所有文件都已经被处理过,只是有些已被确定为无效.根据列数,如果您只有5个左右的10-15列不适用,则无需为同一数据管理两个结构.
现在,您可以看到的另一件事是您是否需要同时定期获取有效和无效文档的信息?如果是这样,那么你真的希望它在一个表中.
如果您不需要一起查询它们,或者文档是"无效",除了历史记录之外不再需要它,那么将它移动到自己的表中是有意义的.
哇,一个问题中有这么多糟糕的建议和设计神话,很难知道从哪里开始。
这是VLDB吗?您是说数百 TB、数百 GB、1-10 GB 吗?
这是一个不太高性能的数据库吗?您需要挤出微秒吗?
大多数建议都倾向于极端,在这种情况下,您可能会为了性能而违反一些基本规则。
之前的一张海报说,
“无论该文档有效还是无效,它仍然是一个文档,因此它们都位于同一个表中具有最初的意义。”
他走在正确的轨道上。就这一点而言,无论它是经过处理还是未经处理,它也是一个文档。我强烈质疑第一个表的分割。
然后他说,
“将两种类型的文档放在同一个表中不会有任何作用,只会减慢查询速度,而且不会立即带来好处。”
我不知道这个建议是基于什么。如果您的 RDBMS 支持索引,则在一定大小的索引下,更多数据将产生非常边际的额外成本,因为您的 B 树会更深一层。如果你从表面上理解他的说法,你应该将表限制为每行n行,并不断创建新行,因为“表中的数据越多 = 查询速度越慢”。我不知道为什么人们坚持这种观念。如果您的查询需要对一种或另一种类型进行全表扫描,那么我们就讨论分区,而不是新表。在 10 亿行表中查找一行比在 100 万行表中查找行要多花费 10 毫秒,因为索引可能只比两者深 1 个 blevel。
另一位海报说,
“5-7 列不适用于无效文档 NOT NULL,因此有效文档需要包含它们。在我看来,由于无效文档中有那么多列为空,因此需要使用不同的表。”
我希望人们能解释其中的原因。它如何证明它的合理性?你会根据什么做出这个决定。4个太多了吗?为什么不?但5个太多了吗?也许他假设您正在使用具有固定字段长度的古老 RDBMS。我不知道。如果将可为空的列放在行的末尾,则无需为它们支付任何费用。中间有一些额外的字节。如果这是一件大事,如果您真的想把这个多 TB 表变得更小……我们将讨论垂直分区……而不是一个全新的表。由于您将扩展 n% 行的长度,因此您需要仔细选择 PCTFREE,或者数据库如何执行此操作。除此之外,可空列几乎没有什么缺点。
那么让我们来谈谈三张桌子的所有缺点。
我假设你的桌子看起来像这样;
A surrogate PK column with a unique index.
A candidate key column with a unique index.
a few foreign keys to 'lookup' tables.
Several data fields.
the 5-7 nullable columns that are filled if a document becomes invalid.
Run Code Online (Sandbox Code Playgroud)
第一个问题是,您将在所有表中拥有 3 个 PK,以确保键是唯一的...但是没有跨表对象来保证所有三个组合的唯一性。除非您煞费苦心地编写将数据从一个表移动到下一个表的代码,否则您可能会拥有相同的文档两次或更多次。每桌一次。如果您有一个原始表、已处理表和无效表,那么就不可能发生这种情况。
使用三个表,您的所有约束都将被一遍又一遍地验证。当您向原始表中插入数据时,PK 会被验证,AK 会被验证,FK 会被验证,其他列也会被验证。所有索引中都为这些新条目腾出了空间,可能会导致块分裂。现在,您处理文件并从原始表中删除条目,所有这些索引都会被删除,留下空白空间。您在下一个表中的插入将再次承受第一次插入的所有成本。您的索引会受到影响,可能会导致块分裂,您的 PK、AK 和 FK 都会再次得到验证。对无效表重复泡沫冲洗。
现在,如果您发现业务需要第四种状态时采用这种范例,您的数据模型会发生什么?您将为处于未提交状态或已发送状态的文档添加第四个文档表。毕竟,新的发送状态有 5-7 个其他状态不需要的列。
并且有很多查询变得很容易在多个表中编写和运行,而在单个表中,它们是清晰、简洁和快速的......表的大小实际上只会影响全表扫描,我们尽量避免对表进行全表扫描像这些。
我见过这样的系统。一个主要的操作查询是“我的文档在哪里?”
您必须搜索 3 个表才能找到其状态。大多数人接下来要做的就是构建所有三个表的 UNION ALL 视图,以方便解决诸如此类的无数问题。如果其他发帖者认为您的查询因表中的其他数据而变慢,请查看当您执行 UNION ALL 来完成相同的事情时它们实际上如何变慢。blevel 3 的 1 个索引,而不是 blevel 2 的 3 个索引。
我在一家贸易公司工作。我们与交易对手进行交易。出于会计和法律原因,我们公司被定义为多家公司。我们称它们为贸易、控股、合资企业。我们会打电话给我们的交易对手。JonesCo、SmithBarely、GoldSax。
因此,如果我认为内部公司有一组独特的列,而交易对手也有一组独特的列。您可能会说,适当的标准化会迫使它们分成两个表。那么让我们这样做吧。
INT_CO_T 1 贸易 2 控股 3 合资
CNTR_PTY_T 1 JonesCo 2 Smith 勉强 3 GoldSax
现在我需要一个交易表,用于映射我们公司和交易对手之间的交易
TRADE_T(Int_co_T.ID、Ctr_pty_T.ID、其他交易列)
伟大的。
糟糕,Business 表示 JointVenture 将与 Trading 执行交易。顺便说一句,这是一个非常常见的情况,这种情况一直在发生。交易公司将这些交易称为账面交易。
现在我有两个选择。(三真)但是。
1 是我可以做一些非常愚蠢的事情,将 JointVenture 和 Trading 放入 Counterparty 表中,这样我的映射表仍然可以工作。这会导致噩梦般的询问,我相信参与这次对话的人都会意识到这一点。或者我可以建立一个单独的映射表..如果我想查看给定公司的所有交易,这也会导致一些联合。
第三种也是更好的方法是为交易对手和内部公司构建一个表,称为 Trading_entities 或其他表。现在我需要一张映射表来显示内部或外部交易。我可以通过一个查询、两张表轻松查看净头寸和净敞口。ETC。
如果您确实对可空字段很感兴趣,那么垂直分区该表并使用三个表。但主表将有一个列表,最重要的是,对于交易参与者的任一子类型都有一个键。