- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我将要构建一个sql数据库,它将包含数十万个对象的统计计算结果。计划使用postgres,但这个问题同样适用于mysql。
例如,假设我有50万个电话记录。现在,每个PhoneCall
都将通过后台作业系统进行统计计算。例如,aPhoneCall
具有以下统计信息:call_duration
:秒(浮动)setup_time
:秒(浮动)dropouts
:检测到音频丢失的时段(数组),例如[5.23, 40.92]
hung_up_unexpectedly
:真或假(布尔值)
这些只是简单的例子;实际上,统计数字更为复杂。每个统计都有一个与之关联的版本号。
我不确定这类计算数据的哪种存储模式最有效。不过,我并没有考虑完全规范化数据库中的所有内容。到目前为止,我已经提出了以下选择:
选项1-一列中的长格式
我将统计名称及其值分别存储在一列中,并引用主事务对象。值列是一个文本字段;该值将被序列化(例如,作为json或yaml),以便可以存储不同类型(字符串、数组等)。统计表的数据库布局为:statistic_id
(主键)phone_call_id
(FK)statistic_name
(字符串)statistic_value
(文本,序列化)statistic_version
(整数)created_at
(日期时间)
我使用这个模式已经有一段时间了,它的优点是我可以根据电话和统计名称轻松筛选统计数据。我还可以轻松地添加新的统计类型,并按版本和创建时间进行筛选。
但在我看来,值的(反)序列化使得它在处理大量数据方面效率很低。此外,我不能在sql级别执行计算;我总是必须加载和反序列化数据。或者postgres中的json支持有那么好,这样我仍然可以选择这个模式吗?
选项2-统计作为主要对象的属性
我还可以考虑收集所有类型的统计名称,并将它们作为新列添加到phone call对象中,例如:id
(主键)call_duration
setup_time
dropouts
hung_up_unexpectedly
…
这将是非常有效的,每个列都有自己的类型,但是我不能再存储不同版本的统计信息,也不能根据它们创建的时间进行筛选。整个统计的商业逻辑消失了。添加新的统计数据也不太容易,因为这些名称都是内置的。
选项3——不同列的统计信息
这可能是最复杂的。我只存储一个对统计类型的引用,该列将根据该引用进行查找:statistic_id
(主键)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
(主键)version
created_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_*
表?我的应用程序必须确保没有重复的条目存在。
总而言之,给定这个用例,什么是在关系数据库中存储数百万个统计值(例如PASGRESs)的最有效的方法,当需求是统计类型可以被添加或改变,并且同时存在多个版本,并且值的查询应该是有效率的吗?
最佳答案
IMO可以使用以下简单的数据库结构来解决您的问题。
统计类型词典
一个非常简单的表-只是stat.type的名称和描述:
create table stat_types (
type text not null constraint stat_types_pkey primary key,
description text
);
jsonb
字段具有与其类型相关的任意stat.data。例如,这样的电话表:
create table phone_calls_statistics (
phone_call_id uuid not null references phone_calls,
stat_type text not null references stat_types,
data jsonb,
constraint phone_calls_statistics_pkey primary key (phone_call_id, stat_type)
);
create table phone_calls (
id uuid not null constraint phone_calls_pkey primary key
-- ...
);
phone_calls
字段有不同的结构,这取决于它的stat.type。通话持续时间示例:
{
"call_duration": 120.0
}
{
"dropouts": [5.23, 40.92]
}
insert into phone_calls_statistics values
('9fc1f6c3-a9d3-4828-93ee-cf5045e93c4c', 'CALL_DURATION', '{"call_duration": 100.0}'),
('86d1a2a6-f477-4ed6-a031-b82584b1bc7e', 'CALL_DURATION', '{"call_duration": 110.0}'),
('cfd4b301-bdb9-4cfd-95db-3844e4c0625c', 'CALL_DURATION', '{"call_duration": 120.0}'),
('39465c2f-2321-499e-a156-c56a3363206a', 'CALL_DURATION', '{"call_duration": 130.0}'),
('9fc1f6c3-a9d3-4828-93ee-cf5045e93c4c', 'UNEXPECTED_HANGUP', '{"unexpected_hungup": true}'),
('86d1a2a6-f477-4ed6-a031-b82584b1bc7e', 'UNEXPECTED_HANGUP', '{"unexpected_hungup": true}'),
('cfd4b301-bdb9-4cfd-95db-3844e4c0625c', 'UNEXPECTED_HANGUP', '{"unexpected_hungup": false}'),
('39465c2f-2321-499e-a156-c56a3363206a', 'UNEXPECTED_HANGUP', '{"unexpected_hungup": false}');
select
avg((pcs.data ->> 'call_duration')::float) as avg,
min((pcs.data ->> 'call_duration')::float) as min,
max((pcs.data ->> 'call_duration')::float) as max
from
phone_calls_statistics pcs
where
pcs.stat_type = 'CALL_DURATION';
select
sum(case when (pcs.data ->> 'unexpected_hungup')::boolean is true then 1 else 0 end) as hungups
from
phone_calls_statistics pcs
where
pcs.stat_type = 'UNEXPECTED_HANGUP';
关于sql - 高效的存储模式,可存储数百万个不同类型的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54627164/
我正在尝试编写一个相当多态的库。我遇到了一种更容易表现出来却很难说出来的情况。它看起来有点像这样: {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE
谁能解释一下这个表达式是如何工作的? type = type || 'any'; 这是否意味着如果类型未定义则使用“任意”? 最佳答案 如果 type 为“falsy”(即 false,或 undef
我有一个界面,在IAnimal.fs中, namespace Kingdom type IAnimal = abstract member Eat : Food -> unit 以及另一个成功
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: What is the difference between (type)value and type(va
在 C# 中,default(Nullable) 之间有区别吗? (或 default(long?) )和 default(long) ? Long只是一个例子,它可以是任何其他struct类型。 最
假设我有一个案例类: case class Foo(num: Int, str: String, bool: Boolean) 现在我还有一个简单的包装器: sealed trait Wrapper[
这个问题在这里已经有了答案: Create C# delegate type with ref parameter at runtime (1 个回答) 关闭 2 年前。 为了即时创建委托(dele
我正在尝试获取图像的 dct。一开始我遇到了错误 The function/feature is not implemented (Odd-size DCT's are not implemented
我正在尝试使用 AFNetworking 的 AFPropertyListRequestOperation,但是当我尝试下载它时,出现错误 预期的内容类型{( “应用程序/x-plist” )}, 得
我在下面收到错误。我知道这段代码的意思,但我不知道界面应该是什么样子: Element implicitly has an 'any' type because index expression is
我尝试将 SignalType 从 ReactiveCocoa 扩展为自定义 ErrorType,代码如下所示 enum MyError: ErrorType { // .. cases }
我无法在任何其他问题中找到答案。假设我有一个抽象父类(super class) Abstract0,它有两个子类 Concrete1 和 Concrete1。我希望能够在 Abstract0 中定义类
我想知道为什么这个索引没有用在 RANGE 类型中,而是用在 INDEX 中: 索引: CREATE INDEX myindex ON orders(order_date); 查询: EXPLAIN
我正在使用 RxJava,现在我尝试通过提供 lambda 来订阅可观察对象: observableProvider.stringForKey(CURRENT_DELETED_ID) .sub
我已经尝试了几乎所有解决问题的方法,其中包括。为 提供类型使用app.use(express.static('public'))还有更多,但我似乎无法为此找到解决方案。 index.js : imp
以下哪个 CSS 选择器更快? input[type="submit"] { /* styles */ } 或 [type="submit"] { /* styles */ } 只是好
我不知道这个设置有什么问题,我在 IDEA 中获得了所有注释(@Controller、@Repository、@Service),它在行号左侧显示 bean,然后转到该 bean。 这是错误: 14-
我听从了建议 registering java function as a callback in C function并且可以使用“简单”类型(例如整数和字符串)进行回调,例如: jstring j
有一些 java 类,加载到 Oracle 数据库(版本 11g)和 pl/sql 函数包装器: create or replace function getDataFromJava( in_uLis
我已经从 David Walsh 的 css 动画回调中获取代码并将其修改为 TypeScript。但是,我收到一个错误,我不知道为什么: interface IBrowserPrefix { [
我是一名优秀的程序员,十分优秀!