2

在开发用于热力学模拟的软件(在 C++ 中)时,我需要存储不同温度下的流体特性。这些数据点用于构建一个简单的插值函数,以便在我们没有完整实验数据的温度下评估属性值。

流体仅通过其名称浓度 (%)来识别(后者通常不相关)。如果你好奇的话,有四个特性很有趣:质量密度动态粘度比热容热导率。对于任何其他意图和目的,这些只是 4 个数字属性,分别称为 A、B、C 和 D。因此,特定流体的函数看起来像这样:(A,B,C,D) = f(T),其中 T 是温度。

目前,它是一个 SQLite3 数据库,流体表如下所示:

+----+-------+---------------+
| id | name  | concentration |
+====+=======+===============+
|  1 | Water |           100 |
+----+-------+---------------+
|  2 | ..... |           ... |

还有属性表:

+----------+-------------+---------+-----------+--------------+----------+
| fluid_id | temperature | density | viscosity | conductivity | capacity |
+==========+=============+=========+===========+==============+==========+
|        2 | 373.15      | 1045.48 | 0.412     | 1.415        | 0.845    |
|        3 | 273.15      | 1105.0  | 2.113     | 0.4688       | 0.849    |
|        3 | 283.15      |         | 1.678     | 0.4859       | 0.8503   |
|        3 | 293.15      | 1098.0  | 1.353     | 0.5015       | 0.5833   |
|        3 | 303.15      |         | 1.08      | 0.5164       |          |
|        3 | 313.15      | 1090.0  | 0.893     | 0.532        | 0.8561   |
|        3 | 323.15      |         | 0.748     | 0.5432       |          |
|        3 | 333.15      | 1080.0  | 0.644     | 0.5543       | 0.8577   |
|        3 | 343.15      |         | 0.563     | 0.564        |          |
|        3 | 353.15      | 1068.0  | 0.499     | 0.5722       | 0.8612   |
|        3 | 363.15      |         | 0.44      | 0.5796       |          |
|        3 | 373.15      | 1054.0  | 0.39      | 0.5856       |          |
+----------+-------------+---------+-----------+--------------+----------+

手动插入数据进行测试是可以的。这也将是稍后流体编辑器 GUI 的直观显示。

然而,在代码中,插值是针对每个属性单独完成的。此外,由于我不能使用 NULL 值,因此并非所有温度(行)都与所有属性相关。为了适应代码的观点,我创建了四个相同的视图——每个属性一个。例如:

+----+-----------+---------------+-------------+-------+
| id |   name    | concentration | temperature | value |
+====+===========+===============+=============+=======+
|  2 | Sea Water |            22 | 373.15      | 0.412 |
|  3 | Sea Water |            14 | 273.15      | 2.113 |
|  3 | Sea Water |            14 | 283.15      | 1.678 |
|  3 | Sea Water |            14 | 293.15      | 1.353 |
|  3 | Sea Water |            14 | 303.15      | 1.08  |
|  3 | Sea Water |            14 | 313.15      | 0.893 |
|  3 | Sea Water |            14 | 323.15      | 0.748 |
|  3 | Sea Water |            14 | 333.15      | 0.644 |
|  3 | Sea Water |            14 | 343.15      | 0.563 |
|  3 | Sea Water |            14 | 353.15      | 0.499 |
|  3 | Sea Water |            14 | 363.15      | 0.44  |
|  3 | Sea Water |            14 | 373.15      | 0.39  |
+----+-----------+---------------+-------------+-------+

现在,随着我逐渐从原型设计转向构建合适的软件,我正在尝试思考这两种方法中的任何一种如何适合 ORM 视角。它是每个属性的模型(如我的视图)还是所有属性的单个模型(如当前使用的表)。第三种选择可能是保留数据库原样并在视图(而不是真实表)之上构建模型,但这不是 ORM 的方式。

我什至考虑将这个数据集移动到 NoSQL 解决方案(例如 MongoDb),但我想不出克服双重视角问题的方法。

我承认这里既没有运行时也没有空间性能问题,而且要存储和处理的数据量无论如何都可以忽略不计。一小时内可能只有两个查询,每个查询将特定流体的数据集加载到应用程序的内存中并在那里使用它(基于评估的插值和计算)。因此,如果您认为我对此压力过大,我会接受。

否则,我想听听您的想法并考虑您可能提供的任何不同方法。我错过了什么吗?拆分表会产生的冗余键(流体和温度)如何?此外,这可能对其他确实设置了约束的人感兴趣。

4

1 回答 1

1

每个带有 NULL 的表都表示“缺失”(“未知”或“不适用”)值,对应于一个模式,该模式删除 NULLable 列并引入另一个表,其中包含原始的某些(超级)键,并且仅在该列中保留不为 NULL 的行它。

Null 支持更轻松的人工同时读取这些单独的相同(超级)键表。但是它们使其他一切变得复杂,包括表的含义(一行进入或退出的标准/谓词),因此基础设计和查询组合。通常我们会尽快删除任何未粘贴到键的 NULL,以便在最终输出中显示。(例如,OUTER JOIN 通常习惯性地用于引入然后删除 NULL 以表示无 NULL EXCEPT/MINUS。)我们使用单独表的含义来表达具有 NULL 的表的含义和使用它的查询的含义。我们从组合的 NULL 视图中提取单独的表以进行基本上任何处理。

直接的关系解决方案是单独的表。SQL 传统是针对一张表。其他 SQL 理由是通过组合表来减少 JOIN。但这仅适用于最终的人类可读输出!要处理一张表,您无论如何都必须提取单独的视图。

PS Re“拆分表会产生的键(流体和温度)冗余”:在列,表或数据库中多次出现相同(子行)值时
没有“冗余”。当两个基表或行做出相同的断言时,就会发生冗余。替换为标准/谓词的行给出了陈述/命题;当前行断言其,而缺席行断言非其;表(命题)断言其存在行和不存在行的断言的合取。(并且数据库(命题)断言其表命题的合取。)此外,冗余不一定是坏的;在时间、空间和复杂性之间总是存在工程权衡。

PPS
ORM 有视图:延迟或延迟查询评估。由于您以后可以在另一个查询中使用这样的查询,它的作用就像一个视图。它是 ORM 查询语言而不是 DBMS 查询语言中查询的命名表示。可以想象,这可以用于更新命令(如果可能)以及查询。这取决于 DBMS/ORM。然而,视图更新基本上是一种方便,因为它总是可以用对组成表的更新来表示。

于 2015-11-14T23:48:22.153 回答