这些表设计中哪一个对性能更好?


16

我被要求创建一些东西来跟踪每天在帐户上收取的费用,而我正在尝试找出一个支持此目的的数据库表模式。

这就是我所知道的

  • 公司拥有超过250万个帐户
  • 其中,他们目前平均每月工作200,000(随着人员配备水平的变化而变化,目前水平很低)
  • 他们想跟踪13种不同的费用类型,并且警告说,将来可能会增加更多的费用
  • 他们希望每天跟踪费用
  • 成本不会在整个库存中分配。它们可以分为每月工作的帐户数量(200,000),或者用户可以输入帐户标识符以将成本应用于一组帐户,或者可以仅指定将成本应用于哪个帐户。

我首先想到的是规范化的数据库:

帐户ID
日期
CostTypeId
量

我的问题是数学。该表将迅速变得庞大。假设所有13种成本类型都应用到了当月的所有工作帐户,即每月200k * 13 * N days in month大约75-8000万条记录,或者每年接近10亿条记录。

我的第二个想法是将其标准化

帐户ID
日期
总计花费
CostType1
CostType2
CostType3
CostType4
CostType5
CostType6
CostType7
CostType8
CostType9
CostType10
CostType11
CostType12
CostType13

此方法更加不200k * N days in month规范,每月最多可以创建600万条记录(),或每年大约7200 万条。它比第一种方法少很多,但是,如果公司将来决定使用新的费用类型,则需要添加另一个数据库列。

在这两种方法中,您更喜欢哪一种?为什么?您是否可以想到另一种更好的选择?

我最感兴趣的是报告性能,包括总结报告和详细报告。当没有人在附近时,将费用分摊到各个帐户的工作将每晚进行。第二个问题是数据库大小。现有的数据库已经接近300GB,我相信磁盘上的空间约为500GB。

该数据库是SQL Server 2005


因此,获得另一个磁盘。磁盘很便宜。您可以花2 TB作为会议费用来讨论此事。

Answers:


9

每年有十亿条记录并不多。

通过分区(可能是每个Costtype)进行分区和归档是可管理的。

要存储的数据项数量仍然是200k * 13 *N。作为列,您将获得每页更少的行,并且它将比行占用更多的空间。如果“ CostType1”不是固定长度的数据类型,但它是边际的,则可能会有所帮助。

正如他们所说的“吻”


3
我绝对建议@Rachel我建议使用如此大的数据集来实现分区模式。如果他们专注于每月工作和报告,那么最好选择与该思维方式一致的分区键。另外,如果正确配置了分区,则可以轻松地将数据从表切换到暂存表,以及将数据从暂存表切换到暂存表,这将导致大量数据加载和删除滚动数据集,而只需几秒钟而不是几小时即可完成。
大卫,

6

虽然您的设计肯定可以使白天或晚上有所作为,但在这种情况下,我将重点放在索引上,包括根据需要覆盖索引。我还将看一下SQL Server为您提供的一些用于处理非常大的表的工具,例如表分区。

可以这样考虑,即使表中有800亿条记录,并且具有正确的索引编制,您在任何给定时间实际感兴趣的记录也会在磁盘上物理分组。由于数据是在SQL Server中组织的,因此按索引边界划分的数据也可能在另一个表中,因为它不必读取整个表即可获得所需的数据。

如果您还选择对表进行分区,则可以缩短访问时间和插入时间。


4

我会正常化。我们对一家银行的客户帐户获利能力进行了成本核算,并使用数百个驱动程序生成了2.5亿行个人成本,这些驱动程序由成本中心,总账或各种其他技术分配给每月数百万个帐户。

例如,根据使用的相对数量,在使用ATM的帐户之间划分了服务ATM的总费用。因此,如果花了100万美元维修ATM,而只有5个客户每次使用一次,而一个客户使用了5次,那么一位客户向银行支付了50万美元,另一位客户向银行支付了10万美元。其他驱动程序可能要复杂得多。

最终,您可能会发现它很稀疏-某些帐户没有从某些来源/驱动程序获得成本-某些帐户没有得到任何东西。在规范化模型中,这些行不存在。在非规范化模型中,存在该行,其中包含一些空列。另外,在稀疏归一化模型中,您应该看到性能有所提高,因为与检查特定“存储桶”中所有非NULL的行相比,检查行的存在(使用CostType覆盖索引)通常更快(即使使用每个金额列上的索引-您可以看到它开始变得非常浪费)。


稀疏-这是一个非常重要的方面,可以使所有方面有所不同。如果稀疏,则可以通过规范化来节省空间。否则,不会。但是磁盘空间很便宜,因此我个人投票赞成最大的灵活性(标准化)。

3

无论性能如何提高,我都肯定会选择选项1。我认为,选项2会抢夺Peter的薪水。


2

我会选择选项1,然后如果以后报告速度成为问题,我还要添加表2,并通过某种自动化的过夜/非高峰期过程将其填充到报告数据库中。

然后,您还可以考虑将每日Table-2结构汇总为进一步的每周,每月,每季度和每年汇总。

但是,正如我所说,我还将选择以适当的(规范化)格式存储“原始”数据。


0

考虑到您提到的数量,我将选择第二种选择,但没有TotalCost。您可以说这仍然是标准化的。


编辑:作为替代方案,并且根据您的要求和AccountId的大小,您还可以考虑以下事项:

AccountDate
-----------
AccountId  
Date  
AcDtID (surrogate key)

Costs
-------
AcDtID
CostTypeId  
Amount  

通过这种设计,您仍然可以在第一个表上添加非规范化的TotalCost,并在每晚进行重新计算,从而允许仅在第一个表上运行一些报告。


我之所以TotalCost在这里,是因为大多数报告都是汇总的,我认为查询单个值比添加13个不同值要快。

可能吧,但是随后您真的引入了传递依赖。这些记录会被更新吗?还是只是写然后才读?

只要在该日期范围内应用了新费用,记录就会更新。大约一个月后,总费用不太可能会更新,但是由于每年的支持费等因素,仍然有可能更新。

然后,每个更新将需要2次更新,并且TotalCost字段会增加不一致的风险。

传递依存关系,但不一定存在不一致的风险-CHECK()约束可以保证TotalCost始终是成本之和。
Mike Sherrill'Cat Recall'

0

您实际上应该将firs表分为两个表,以便可以使用子查询并选择第二行作为一列或多列。这样更加灵活,这样您就可以更轻松地获得类似于第二个结果。

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.