具有结构类型的平面数据与文档存储

Posted

技术标签:

【中文标题】具有结构类型的平面数据与文档存储【英文标题】:Flat data with struct type vs document store 【发布时间】:2020-08-06 19:19:09 【问题描述】:

我知道这是一个“软”问题,通常不赞成 SO,但我一直在使用 BigQuery 对包含结构和重复数据的(显然)平面数据进行数据分析。让我们使用一个非常基本的示例,一行可能如下所示:

身份证 职称 (str) 发布年份 (int) 类型 (str[]) 学分 (struct[])

一个示例数据可能如下所示:


    "ID": "T-1997",
    "Title": "Titanic",
    "ReleaseYear": 1997,
    "Genres": ["Drama", "Romance"],
    "Credits": 
        "Actors": ["Leonardo DiCaprio", "Kate Winslet"],
        "Directors": ["James Cameron"]
    

我的问题基本上是在原生文档存储(例如 MongoDB 或 CouchBase)中可以完成哪些类型的操作或查询,而在支持任意嵌套数据的关系数据库中则无法完成。换句话说,我的假设(我希望我是错的或被误导的)是只要数据库支持结构,它就可以做文档存储可以做的所有事情。如果不是,那么它在哪些地方:(1)可以在 MongoDB(或任何其他文档存储)中完成而在 BigQuery(或任何其他支持结构的数据库)中无法完成的事情? (2) 在 MongoDB 中比在关系数据库中更容易完成的事情?

【问题讨论】:

这个问题可能更适合softwareengineering.stackexchange.com 【参考方案1】:

在原生文档中可以进行哪些类型的操作或查询 存储,例如 MongoDB 或 CouchBase,无法在 支持任意嵌套数据的关系型数据库。

即使 BigQuery 支持任意嵌套数据,与 MongoDB 相比,BigQuery 也允许有限的嵌套。MongoDB 支持更多级别的嵌套。 在 BigQuery 中,您的架构不能包含超过 15 层的嵌套 STRUCT。 MongoDB 支持多达 100 级的 BSON 文档嵌套。

换句话说,我的假设(我希望我是错误的或被误导的)是 只要数据库支持结构,它就可以做任何事情 document-store 可以。

不完全是 - 嵌套列是列中的列。但与 Mongo 这样的 NoSQL 数据库相比,RDBMS 中的分片是一项复杂的工作。从技术上讲你可以做到,但它不是为同样的目的而设计的。就像用扳手当锤子一样——当然可以,但它的目的是不同的。您应该为正确的目的使用正确的工具。

如果不是,它在哪些地方:(1) 可以在 MongoDB(或任何其他文档存储)中完成 在 BigQuery(或任何其他支持结构的数据库)中完成?和 (2) 在 MongoDB 中可以比在 关系型数据库?

问题的关键在于,RDBMS 可能会添加一些功能以“从技术上”让您做一些可以在 NoSQL 数据库中做的事情。但这并不意味着它可能同样有效。例如,由于使 RDBMS 成为 RDBMS 的特性(ACID 合规性、事务等),与 NoSQL 数据库相比,总会有额外的性能损失。如果 RDBMS 删除了这些功能,那么它就不再是 RDBMS!

这个答案说明了 MongoDB 如何获得更好的性能,因为它不需要支持 RDBMS 功能:

https://softwareengineering.stackexchange.com/questions/54373/when-would-someone-use-mongodb-or-similar-over-a-relational-dbms

MongoDB 每次查询的延迟更低,每次查询花费的 CPU 时间也更少,因为它做的工作少得多(例如,没有连接, 交易)。 因此,它可以处理更高的每秒查询负载,因此经常在您拥有大量用户的情况下使用。 MongoDB 更容易分片(在集群中使用),因为它不必担心事务和一致性。 - MongoDB 有一个 更快的写入速度,因为它不必担心 事务或回滚(因此不必担心 锁定)。 MongoDB 没有架构,以防您有特殊用例可以利用它。

另一个特性是分片 - 使用 mongodb 分片更容易,因为它不需要支持许多使 RDBMS 成为 RDBMS 的特性,例如符合 ACID。相比之下,RDBMS 的分片很复杂,因为 RDBMS 必须保持 ACID 兼容。

看看下面两张图片:

快艇在水中的性能是“水陆两用车”的 10/10 倍。水陆两用车在技术上可以在水中航行,但它并非设计用于,因此速度较慢且不适合其用途。

同样,看看快艇和这款可爱的汽车在空气动力学方面的差异。即使你把***钉在船上,它在陆地上的表现也不会像这辆车那样好。 (打个比方,你可以说 NoSQL 数据库不进行连接 - 你必须自己实现它们。 - 但是对于连接繁重的操作,它会比 RDBMS 执行得更好吗?)

我用类比的意思是,每种数据库最初都是为特定目标设计的,随着时间的推移,已经添加了一些功能来尝试解决它不是为它设计的问题(因此它没有不要像专门为此目的而设计的那样做)。

因此,在您的问题中,即使 BigQuery 或某些 RDBMS 可以做某事这并不意味着您应该使用它们来完成这项工作。这同样适用于 NoSQL 数据库。你应该使用最好的工具来完成这项工作。

【讨论】:

很好的答案,感谢您抽出宝贵的时间。我已经给你赏金了。出于好奇,您是否想在代码/查询中展示一个示例,其中关系数据库中的某些事情在 noSQL 存储中是微不足道的? @谢谢大卫。要回答您的问题,在关系数据库中查询任何内容并不困难 - 事实上,在关系数据库中查询对于大多数事情来说应该更容易,因为您受益于连接等和强大的语言。不同之处在于,由于缺少事务等,NoSQL DB 中的性能有时可能比 RDBS 更快。例如,在 RDBMS 中,很容易编写带有连接的查询。在 NoSQL DB 中,您需要自己编写连接。关于性能,NoSQL DB 中的任意查询可能会更快,因为没有事务。【参考方案2】:

免责声明:我没有使用 MongoDB 或 CouchBase 的经验。我的回答是基于 BigQuery 在 STRUCT 上的能力。

性能

BigQuery 的 STRUCT 针对查询进行了优化。比如查询select a.nested_b.nested_c.nested_d from table_t,查询只扫描左侧STRUCT字段nested_d的数据,既快又便宜。

可用性

如果您的数据是一次写入或仅追加,则 STRUCT 列与文档存储 AFAIK 相当。

但是如果你想稍后只更新某些嵌套字段,嵌套的 STRUCT 很难做到,因为没有办法更新重复字段中的单个项目,你必须加载整个数组,扫描和更改,并且重新打包以更新列。您将编写如下内容:

UPDATE table
SET Credits.Actors = (SELECT ARRAY_AGG(...) FROM UNNEST(Credits.Actors) WHERE ...)
WHERE ... 

当存在数组结构的数组(甚至更多嵌套级别)时,这可能会成为一个更大的问题。根据我对文档存储的理解,更新文档的单个嵌套字段应该比这更容易。基本上,这是为了获得前面提到的性能优势而必须付出的代价。

【讨论】:

面向文档的数据库也可以针对查询进行优化。例如,Couchbase 和 MongoDB 都支持优化查询的索引。

以上是关于具有结构类型的平面数据与文档存储的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB简介与增删改查

关系数据库中如何存储xml数据?

ElasticSearch实战-复合数据类型

ElasticSearch实战-复合数据类型

嵌套结构如何影响 DocumentDB 查询性能?

MongoDB:数据类型插入文档查询文档