有效的方法来跟踪SQL Server中许多列的总量

时间:2010-11-29 00:35:36

标签: sql-server

这是一个很长的问题,我不知道如何总结......

我有一张表需要阅读,其中包含有近十亿条详细数据记录的财务数据。我不能改变这个表的结构,我只是它的消费者。此表包含诸如事务数据,一组属性列以及描述事务的Int数据的列(未命名为Attribute1-20,下面仅为简单命名),然后是Amount列。

TABLE: FinancialData
COLUMNS:
  Id (BigInt IDENTITY)
  TransactionId (Int FK)
  TransactionDate (DateTime)
  Attribute1 (Int)
  Attribute2 (Int)
  .
  .
  Attribute20 (Int)
  Amount (Decimal)

我有一个流程需要将此FinancialData表汇总为2个数据库表(一个是头表,另一个是具有聚合量的详细表),用于用户定义的时间线,以便可以使用数据的快照通过其他过程。标头表包含每个用户定义的时间线(快照)的一条记录,详细信息表包含FinancialData表的所有属性的汇总金额记录。

TABLE: FinancialHeader 
COLUMNS:
  Id (Int IDENTITY)
  BeginTransactionDate (DateTime)
  EndTransactionData (DateTime)


TABLE: FinancialDetail
COLUMNS:
 Id (Int IDENTITY)
 FinancialHeaderId (Int FK)
 Attribute1 (Int)
 Attribute2 (Int)
 .
 .
 Attribute20 (Int)
 Amount (Decimal)

举一个这个过程的例子,比较说FinancialData表中有2000万条记录,其中TransactionDate介于2010年1月1日到2010年6月30日之间,有许多冗余属性(但是它们会有不同的TransactionId值)。如果我在上面的FinancialHeader和FinancialDetail表中总结这些数据,我将创建一个FinancialHeader记录,其BeginTransactionDate为1/1/2010,EndTransactionDate为6/30/2010,然后是多个FinancialDetail记录,这些记录是头。 FinancialDetail表聚合来自FinancialData的2000万条记录,基本上包含一组Attribute1 - Attribute20的唯一值以及SUM(Amount)来跟踪这些属性的总量。通常,FinancialData表中的2000万条记录将包含大约10,000个唯一的属性组合,这些组合将在FinancialDetail表中生成10,000条记录,并带有汇总金额。因此,在我的示例中,将有1条FinancialHeader记录和在此过程中创建的大约10,000条FinancialDetail记录。

我的问题涉及存储20列属性数据的唯一组合......我正在谈论的这个“快照”过程可以由用户反复运行多次,以适应不同的日期范围基本上存储该时间段的金额。那么会发生什么是FinancialDetail表中包含大量数据,即使它是聚合数据。我不喜欢的是我创建的FinancialDetail表中有20列,我觉得可能会浪费空间。我所想的可能是更好的方法是将每个唯一的属性组合存储到另一个表中的行中,比如称为FinancialAttribute,它包含一个Id列,然后可以将其用作FinancialDetail表的查找机制。所以FinancialAttribute表看起来像这样:

TABLE: FinancialAttribute
COLUMNS: 
  Id (Int IDENTITY)
  Attribute1 (Int)
  Attribute2 (Int)
  .
  .
  Attribute2 (Int)

FinancialDetail表将被修改为:

TABLE: FinancialDetail
COLUMNS:
 Id (Int IDENTITY)
 FinancialHeaderId (Int FK)
 FinancialAttributeId (Int FK)
 Amount (Decimal)   

这是一种非常常见的模式来处理跨多个列/属性的聚合吗?或者我是以完全错误的方式思考这个问题?我需要以某种方式将FinancialData表中的数据存储到我自己的本地副本中,因为有几个下游进程需要处理或报告这些用户定义的此财务信息的时间线快照。

3 个答案:

答案 0 :(得分:2)

这是减少报告数据占用的存储量的一种相当普遍的方法 - 它的一种形式是用于数据仓库设计的星型模式模式的核心,其中(简化)措施( (方案中的财务金额)存储在事实表中,提供上下文的静态数据(属性列)存储在维表中。

额外要求是维护FinancialAttribute表;假设将来会在数据中显示新的属性组合,您需要将它们添加到FinancialAttribute,以便它们可以链接到FinancialDetail。根据您当前报告流程的实施情况,这可能只是一个简单的更改。

答案 1 :(得分:1)

您提议的FinancialAttribute表不应包含每个属性的字段,因为

  • 存储效率低(许多属性值为NULL)
  • 很难找到作为参数的属性的数据:SELECT ... WHERE attr1 = @ parm OR attr2 = @ parm OR attr3 = @ parm ...

你会更好地规范化并创造:

TABLE: FinancialAttribute
COLUMNS: 
  Id (Int IDENTITY)

TABLE: FinancialAttributeValue
COLUMNS: 
  Id (Int IDENTITY)
  FinancialAttributeID int
  Attribute Int

如果Attribute不仅仅是一个标识符:

TABLE: Attribute
COLUMNS: 
  Id (Int IDENTITY)
  AttributeName varchar(50)

答案 2 :(得分:1)

罗嗦的问题,罗嗦的答案! ;)

我不是数据仓库专家,因此我不熟悉该领域的模式(和反模式)。我说的只是一个可能做过类似事情的DB开发者。

就我而言,我们从处方药信息的大型源表中获取快照。快照用于下游分析和报告。用户指定快照标准,如日期和药物类型,通常会影响2米(相对于您的20米)记录。这通常可以编译为120k(相对于您的10k)记录。快照无限期保留,因为源表随时间而变化并且不是历史记录。我分享了对快照拉动和存储冗余信息的担忧。

你的问题 - 你做的事情是愚蠢的吗?还有更好的方法吗?

从概念上讲,很明显你的保理是“安全的”。通过这个,我的意思是它是一个明显正确的直接转换,并且很明显如何将因素版本重新映射到原始版本并且没有什么痛苦。从这个角度来看(概念上的轻松),我认为它有优点。

至于影响,我会考虑预期的表格大小。我的假设是:

  • 平均快照记录=每个快照的唯一属性组合总数= 10k
  • 随时间变化的总数量快照= 10k
  • 随时间变化的总独特属性组合= 100k
  • Amount列精度是< 20位数

所以:

FinancialDetail (orig)
Column   | Type     | Avg Size
-------------------------------
ID       | int      | 4
HeaderID | int      | 4
Amount   | decimal  | 9
A1 - A20 | int x 20 | 80
-------------------------------
Total:                97
Expected num rows:    100m
Total expected size:  9GB


FinancialDetail (new)
Column   | Type     | Avg Size
-------------------------------
ID       | int      | 4
HeaderID | int      | 4
AttribID | int      | 4
Amount   | decimal  | 9
-------------------------------
Total:                21
Expected num rows:    100m
Total expected size:  2GB

FinancialAttribute (new)
Column   | Type     | Avg Size
-------------------------------
ID       | int      | 4
A1 - A20 | int x 20 | 80
-------------------------------
Total:                84
Expected num rows:    100k
Total expected size:  8MB

如果我的假设是在球场(和我的数学权利),你可以节省78%的空间。这不包括索引或表填充松弛的空间,因此实际的表大小会更高。

保存7GB是否重要?

  • 9GB可以通过现代磁盘轻松管理,与主表无比。
  • 无论如何,数据(可能)会在查询中重新放回内存中,因此可能无法通过线路或缓存进行节省。
  • 如果按属性进行搜索
  • ,查询IO应该会更好一些
  • 备份/恢复时间应该更好
  • 重建索引,更新统计数据等的时间应该更好
  • (覆盖)基于属性的索引要小得多
  • 插入到因式表中的查询时间将会上升

你可以自己打电话,但在我看来,如果空间是第一关注的话,你的保理可能是值得的,即使它在技术上不是最好的最佳解决方案。

谈到效率......

如果你以某种方式设法将属性空间优化到0字节,那么你只能再节省0.09%的原始空间。所以我不会在那里进一步优化空间

另一方面,只需删除FinancialDetail.ID并在(HeaderID,AttributeID)上使用PK就可以节省4.1%的原始费用。 (假设:你没有指向这张桌子的FK。)

如果有更好的方法 - 我不知道。这取决于您获得的快照数量,快照的使用方式以及快照的速度。