在数据库中拆分值和参数是否可以

时间:2018-05-23 10:35:49

标签: database postgresql

我想在关系数据库中存储大量数据(在我的案例中,在RDS上使用postgresql),但我不确定要使用哪种结构。我遵循了包括数据库规范化的数据库课程,但我仍然不确定如何构建数据库。

我的数据包括气候模型的表格结果,按区域(水池)汇总。

[temperature,precipitation .. etc.]长度= 11的

参数 [1960 : 2014][1:12]中的月份 区(盆地)[1 : 16000]

选项1

我的第一个选择是为每个指标创建一个单独的表,并按如下方式存储数据:

|  ID   | basin_id | temperature | unit | year | month | temporal_resolution |
|-------|----------|-------------|------|------|-------|---------------------|
|     1 |        1 |        42.1 | k   | 2000 |     1 | month               |
|     2 |        2 |        1.87 | k   | 2000 |     1 | month               |
|    .. |       .. |          .. | ..   |   .. |    .. | ..                  |
| 11001 |        1 |        40.3 | m3   | 2000 |     2 | month               |
| 11002 |        2 |         2.3 | m3   | 2000 |     2 | month               |

选项2

,第二个选项创建一个垂直表:

|  ID   | basin_id |  indicator  | value | unit | year | month | temporal_resolution |
|-------|----------|-------------|-------|------|------|-------|---------------------|
|     1 |        1 | temperature |  42.1 | k   | 2000 |     1 | month               |
|     2 |        2 | temperature |  1.87 | k   | 2000 |     1 | month               |
|    .. |       .. | ..          |    .. | ..   |   .. |    .. | ..                  |
| 11001 |        1 | precipitation |  40.3 | m3   | 2000 |     2 | month               |
| 11002 |        2 | precipitation |   2.3 | m3   | 2000 |     2 | month               |

我的问题是建议还是不应该使用拆分指标名称和值。如果数据垂直存储,则总行数将为appr。 16000 * 11 * 12 * 55 = 116,160,000,我不确定是否易于管理。

选项3

编辑:由于指标数量有限(大约12个),因此不需要垂直表格结构。第三种选择是将不同的指标表合并为:

|  ID   | basin_id | temperature_k | precipitation_m | …  | riverdischarge_m3 | year | month | temporal_resolution |
|-------|----------|---------------|-----------------|----|-------------------|------|-------|---------------------|
|     1 |        1 |          42.1 |            42.1 | …  |              42.1 | 2000 |     1 | month               |
|     2 |        2 |          42.1 |            42.1 |    |              42.1 | 2000 |     1 | month               |
|    .. |       .. |            .. |              .. | .. |                .. |   .. |    .. | ..                  |
| 11001 |        1 |          42.1 |            42.1 | .. |              42.1 | 2000 |     2 | month               |
| 11002 |        2 |          42.1 |            42.1 | .. |              42.1 | 2000 |     2 | month               |

这导致row_count为16000 * 55 * 12 = 10,560,000

2 个答案:

答案 0 :(得分:2)

这似乎是在关系数据库中建模继承的一个示例。

你有一个抽象的实体 - "观察" - 使用属性zoneyearmonth,具体实体" temperature_observation"用温度"属性,"降水"实体用"立方米"。

这个SO question概述了可用的选项 - 它们都不是特别干净。您的选项1是"每个子类的表"。

您的选项2不是常见的解决方案之一;它可供您使用,因为您的数据显然只有2个属性 - 数量(数字)和计量单位。这不是常见的情况。

选项3是"单表继承"。它是一种常见的设计模式,如果您的子类数量有限,通常可以使用;一旦你获得了很多子类,它就变得相当难以理解。

您需要考虑的下一件事是如何查询此数据。这是一个问题"返回给定时期/盆地的所有记录"?在这种情况下,它并不重要 - 你的选择都很好。

如果要将数据库用于更复杂的查询 -

  

哪个月的气温最高,降水量最低?

     

降水所在的盆地的平均温度是多少   至少x?

  • 然后你可能想要赞成"可读性"你的疑问

在我看来,选项1非常清楚 - 任何查看数据库查询的人都会一目了然地了解您所要求的内容。您将加入定义问题域的事物 - 盆地,年,月。

选项2和3需要自连接,随着条件变得更加复杂,这可能会变得相当复杂和难以阅读。

例如,选项1中的问题what's the average temperature in basins where precipitation is at least x?是:

select avg(temperature)
from temperature_facts
where basin_id in 
  (select basin_id
   from precipitation_facts
   where precipitation > ?)

在选项2中,这变为:

select avg(value)
from   facttable
where  indicator = 'temperature'
and    basin_id in 
  (select basin_id
   from fact_table
   where value > ?
   and indicator = 'precipitation')

在选项3中,它类似于

select avg(temperature)
from fact_table
where basin_id in 
  (select basin_id
  from fact_table
  where precipitation > ?)

就个人而言,我发现选项1更具表现力,但这是一个偏好问题。

答案 1 :(得分:1)

由于我们也进行海洋研究,我了解您的需求(也许这是来自CTD的数据)。根据我的经验:

  • 使用单独的年,月,日,小时字段代替date \ datetime字段(分辨率几乎不低于 小时)。
  • 对于使用的不同探针集,一组不同的数据以分隔文本文件的格式出现(顶部标题行)。 导入并稍后进行一些验证,转换 使用每个参数的字段都有意义。
  • OTOH有些情况下,模型需要太多相同类型的数据,我观察到使用非传统方式来存储 事实证明数据要快得多。即:在一个日期范围内(比如说最后5个 年),某个参数是用固定的a期来衡量的 第二。这是每天86400个参数的测量值。 将它乘以5年,你最终会得到接近158的东西 百万价值,仅适用于某个地点。如果你需要存储 对于20个地点,那么你需要超过30亿行的数据 你以传统方式做到这一点。如果它也不影响存储, 我想说这是ETL的问题和之后的分析。 如果你这样做,采用传统方法:

    LocationID(int),Datetime(每秒递增),Value

    它看起来很无辜但只是存储量超过30 Gb。所以我采取了另一种方法并存储:

    LocationId,date(not datetime),oneDayWorthValues(作为二进制,每秒固定,如果值范围适合2个字节,那么每行恰好有86400 * 2个字节的二进制数据) - 我使用的数据库没有数组数据类型。

只需我0.05美分,但如果您也可以做类似的事情(水资源数据很少),也许值得。