星型模式数据仓库中动态字段的EAV替代品


13

我需要在大型数据仓库中支持动态字段和值以存储API请求日志,而我的用例是我需要存储所有API请求查询字符串,并在将来能够对其进行查询(因此,不仅仅是存储,所以我不能为他们使用blob)

例如 http://example.com/?action=test&foo=abc&bar=def...

我需要存储所有field => value映射,即(action => test), (foo => abc), (bar => def),由于该字段是动态的,所以我发现的唯一解决方案是使用Entity-Attribute-Value,但是,人们一直说这是一个非常糟糕的设计。

因此,考虑以上我的用例,什么是EAV的合适替代方案?

我当前使用KAV的架构

  1. requests
    (id, timestamp, uri)
    例如(1, 149382220, '/')

  2. params
    (request_id, key, value)
    例如(1, 'action', 'test'), (1, 'foo', 'abc'), (1, 'bar', 'def')

有什么建议么?

更新:我们在AWS RedShift上运行仓库


2
尝试在开发数据库中提出建议有什么问题?另外,您在谈论SQL Server吗?在SQL标签是非常宽泛的。
马克斯·弗农

更新了我的问题
霍华德

1
您正在使用哪个DBMS?有些具有很好的文本索引功能,因此我不排除使用“长文本”字段来存储请求。话虽如此,使用您建议的模型我不会有任何问题。从严格意义上讲,EAV仅用于此非常特定的目的。再说一遍,您需要执行哪种查询?尝试针对此模型编写这些查询,以查看它是否适合您。
Colin't Hart 2014年

1
您正在使用什么RDBMS?SQL还不够具体。有人问过你两次。我是第三。
Erwin Brandstetter,2014年

2
由于RedShift基于PostgreSQL,我将尝试使用hstoreor json数据类型(或jsonb如果/当它们“升级”到9.4时)。
Colin't Hart

Answers:


11

我可以想到三种解决方案-EAV,XML和稀疏列。后者是特定于供应商的,可能对您没有用。

无论选择哪种方法,都可能希望考虑将原始请求数据以原始格式存储在表或平面文件中。这将使尝试存储数据的新方法变得容易,如果发现解析请求的方式有错误,则可以重新加载数据,并提供使用批处理或“大数据”解析API请求的机会。工具,如果您发现数据仓库无法有效处理数据。

EAV注意事项

如上所述,EAV / KVS可能是最简单的实现。

不幸的是,这也将非常昂贵-要获得对常用键的任何有效查询,您需要在键列上具有索引,这可能会变得非常分散。查询特定密钥将非常昂贵。

通过为实例化视图支持EAV存储库(许多供应商支持此方法)来查询您关心的键或值,您可能能够降低索引编制或索引扫描的成本。

XML格式

大多数企业数据库系统提供非常成熟的XML处理,包括验证,索引编制和复杂的查询。

以XML格式将API请求加载到数据库中后,每个请求将提供一个元组,从逻辑上讲,这比EAV表中的行数未知更可口。

这是否有效将在很大程度上取决于您的RDBMS供应商和您的实现。

最大的缺点是,这可能是管理数据的唯一方法,它比原始请求的字符串处理还要复杂!

稀疏列/传统表

您可能会将数据加载到传统的表结构中,每个键只有一列。

SQL Server的“ 稀疏列”功能是EAV存储的绝佳替代选择。具有稀疏列的表的行为与普通表几乎相同,不同之处在于它最多可以包含30,000个列,并且稀疏列中的NULL值不占用表中的空间。

如果您经常查询几个特定的​​列和/或值,则将它们与筛选索引(SQL Server的另一个特定功能)结合使用可以为EAV存储提供极为有效的替代方法。

与其他供应商一起使用传统表可能是可行的-IBM支持每个表700多个列,Oracle支持大约1000列,并且诸如压缩或Oracle处理尾随空值之类的功能可能意味着您可以相当有效地存储API数据。

这种方法的明显缺点是,当您向API添加新键时,需要相应地调整架构。


2
在PostgreSQL中,我不建议使用XML,但建议使用hstorejson。在接下来的9.4版jsonb将是我的建议。
Colin't Hart 2014年

我真的很喜欢这个答案,每个都有优点和缺点。信息非常丰富-我一定会喜欢“稀疏专栏”的信息。我想要一个使用稀疏列方法的EAV的示例。
StixO

9

就其本身而言,EAV并不是一个糟糕的设计,它只是一种需要大量预见的设计,并且随着数据量的增加,可能会出现性能问题。可能对于您的系统而言,它将运行良好。

当我设计一个用于存储查询字符串的系统时,我事先不知道我会对哪些字段感兴趣。我创建了一个表以串行化的二进制格式存储查询字符串,并构建了一个系统,使我可以将查询分开一旦我知道自己感兴趣的部分,就将其串入组成部分。从那里我创建了一组表;每个通常包含在查询字符串中的一组数据。

例如,我最终有了一个用于引用数据的表,一个用于目标请求数据的表,一个用于与用户相关的项目(例如他们输入的搜索查询)的表。

我发现能够将整个查询字符串作为blob存储在单个表中,同时还提供了将来将该blob分开的功能,很好地满足了我的需求。


1
在问题和答案中BLOB均使用术语“ 二进制长对象”。我更喜欢使用CLOB(Character Long OBject)或类似textPostgreSQL的东西,因为我们在谈论字符而不是二进制数据。
Colin't Hart

2
我使用了一个二进制字段,因为我实际上序列化了整个会话对象,并将整个对象存储在数据库中。
马克斯·弗农
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.