【发布时间】:2019-07-04 17:55:44
【问题描述】:
我即将构建一个 SQL 数据库,该数据库将包含数十万个对象的统计计算结果。计划使用 Postgres,但问题同样适用于 MySQL。
例如,假设我有 50 万条电话记录。现在,每个PhoneCall 都将通过后台作业系统计算统计信息。例如,PhoneCall 具有以下统计信息:
-
call_duration:以秒为单位(浮点数) -
setup_time:以秒为单位(浮点数) -
dropouts:检测到音频丢失的时段(数组),例如[5.23, 40.92] -
hung_up_unexpectedly: true or false (boolean)
这些只是简单的例子;实际上,统计数据更为复杂。每个统计信息都有一个与之关联的版本号。
我不确定这些类型的计算数据的哪种存储模式最有效。不过,我并没有考虑完全规范化数据库中的所有内容。到目前为止,我提出了以下选项:
选项 1 – 一列中的长格式
我将统计名称及其值分别存储在一列中,并引用主事务对象。值列是一个文本字段;该值将被序列化(例如 JSON 或 YAML),以便可以存储不同的类型(字符串、数组等)。统计表的数据库布局为:
-
statistic_id(PK) -
phone_call_id(FK) -
statistic_name(字符串) -
statistic_value(文本,序列化) -
statistic_version(整数) -
created_at(日期时间)
我已经使用这种模式有一段时间了,它的好处是我可以轻松地根据电话和统计名称过滤统计信息。我还可以轻松添加新类型的统计信息,并按版本和创建时间进行过滤。
但在我看来,值的(反)序列化使其在处理大量数据方面效率很低。此外,我无法在 SQL 级别执行计算;我总是必须加载和反序列化数据。还是 Postgres 中的 JSON 支持那么好,所以我仍然可以选择这种模式?
选项 2 – 统计作为主要对象的属性
我还可以考虑收集所有类型的统计名称并将它们作为新列添加到电话对象中,例如:
-
id(PK) call_durationsetup_timedropoutshung_up_unexpectedly- ...
这将非常有效,并且每一列都有自己的类型,但我不能再存储不同版本的统计信息,或者根据它们的创建时间过滤它们。统计的整个业务逻辑消失了。添加新的统计数据也不是一件容易的事,因为名称已经包含在内。
选项 3 – 不同列的统计数据
这可能是最复杂的。我只存储对统计类型的引用,并且将根据该列查找该列:
-
statistic_id(PK) -
phone_call_id(FK) -
statistic_name(字符串) -
statistic_value_bool(布尔值) -
statistic_value_string(字符串) -
statistic_value_float(浮点数) -
statistic_value_complex(序列化或复杂数据类型) -
statistic_value_type(表示bool、string等的字符串) -
statistic_version(整数) -
created_at(日期时间)
这意味着该表将非常稀疏,因为只会填充statistic_value_ 列之一。这会导致性能问题吗?
选项 4 – 标准化形式
尝试规范化选项 3,我将创建两个表:
-
statistics-
id(PK) versioncreated_at
-
-
statistic_mapping-
phone_call_id(FK) -
statistic_id(FK)
-
-
statistic_type_mapping-
statistic_id(FK) -
type(字符串,表示bool、string等)
-
-
statistic_values_boolean-
statistic_id(FK) -
value(布尔)
-
- …
但这不会发生,因为我不能动态加入另一个表名,可以吗?或者我是否应该根据统计 ID 加入所有 statistic_values_* 表?我的应用程序必须确保不存在重复的条目。
总而言之,给定这个用例,当要求可以添加或更改统计类型并且需要多个版本时,在关系数据库(例如 Postgres)中存储数百万个统计值的最有效方法是什么同时存在,那么查询值应该有点效率?
【问题讨论】:
-
(我也愿意接受以下建议:将所有内容转储到 NoSQL DB 或某个集群中。)
-
我在这里遗漏了一件关键的事情,即将对这些数据执行哪些操作(如在哪些查询中)。
-
@RomanKonoval 每个统计类型,如果是数字:平均值、方差、统计检验等。如果它们是字符串:基本上是过滤/分组。
标签: sql database postgresql performance entity-attribute-value