你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
虽然像 Azure Cosmos DB 这样的无架构数据库可以轻松存储和查询非结构化和半结构化数据,但请考虑数据模型,以优化性能、可伸缩性和成本。
如何存储数据? 应用程序如何检索和查询数据? 应用程序是读取频繁,还是写入频繁?
阅读本文后,可回答以下问题:
- 什么是数据建模,我为什么应该关注?
- Azure Cosmos DB 与关系数据库中的数据建模有何不同?
- 如何在非关系型数据库中表示数据关系?
- 我应何时嵌入数据和何时链接数据?
JSON 格式的数字
Azure Cosmos DB 将文档保存为 JSON 格式,因此在将数字存储为 JSON 之前,确定是否需要将数字转换为字符串非常重要。 如果数字可能超出电气和电子工程师协会 (IEEE) 754 binary64 定义的双精度数字的范围,则将所有数字转换为 String。
JSON 规范解释了为什么使用超出此范围的数字会造成互操作性问题,从而导致不良做法。 这些问题对于分区键列尤为重要,因为它不可变,需要数据迁移才能在稍后进行更改。
嵌入数据
对 Azure Cosmos DB 中的数据建模时,请将实体视为使用 JSON 文档表示的自包含项。
为了进行比较,让我们先了解一下关系数据库中的数据建模方式。 下面的示例演示了如何在关系型数据库中存储一个人的信息。
使用关系数据库时,策略是将所有数据规范化。 规范化数据通常涉及到将一个实体(例如某人)的信息分解为多个离散的组成部分。 在示例中,一个人可以有多个联系人详细信息记录,以及多个地址记录。 可以通过提取常见字段(如类型)来进一步细分联系人详细信息。 同样的方法也适用于地址。 每条记录都可以归类为住宅或办公地址。
数据规范化的指导原则是避免在每个记录中存储冗余数据,而是直接引用数据。 在本示例中,若要读取某个人的所有联系人详细信息和地址信息,在运行时需要使用 JOINS 有效地重新撰写(或反规范化)数据。
SELECT p.FirstName, p.LastName, a.City, cd.Detail
FROM Person p
JOIN ContactDetail cd ON cd.PersonId = p.Id
JOIN ContactDetailType cdt ON cdt.Id = cd.TypeId
JOIN Address a ON a.PersonId = p.Id
更新一个人的联系方式和地址需要对多个单独的表进行写入操作。
现在让我们了解如何将相同的数据建模为 Azure Cosmos DB 中的自包含实体。
{
"id": "1",
"firstName": "Thomas",
"lastName": "Andersen",
"addresses": [
{
"line1": "100 Some Street",
"line2": "Unit 1",
"city": "Seattle",
"state": "WA",
"zip": 98012
}
],
"contactDetails": [
{"email": "thomas@andersen.com"},
{"phone": "+1 555 555-5555", "extension": 5555}
]
}
我们已使用上述方法,通过将此人相关的所有信息(例如联系人详细信息和地址)嵌入到单个 JSON 文档,非规范化了其相关记录。 此外,因为我们不受固定架构的限制,所以我们可以灵活地执行一些操作,例如可以具有完全不同类型的联系人详细信息。
从数据库检索一条完整的人员记录现在只需对单个容器中的单个项目执行一次读取操作。 更新人员记录的联系人详细信息和地址也是针对单个项的“单个写入操作”。
对数据执行非规范化操作可能会减少应用程序完成常见操作所需的查询和更新次数。
何时嵌入
通常在下列情况下使用嵌入式数据模型:
- 实体之间存在“包含”关系。
- 实体之间存在“一对多”关系。
- 数据变化不频繁。
- 数据不会无限增长。
- 数据经常被同时查询。
注意
通常非规范化数据模型具有更好的读取性能。
何时不嵌入
虽然 Azure Cosmos DB 的经验法则是将所有数据反规范化并嵌入到单个项中,但是这种方法可能导致一些情况的发生,而这些情况是应该避免的。
以下面的 JSON 代码段为例。
{
"id": "1",
"name": "What's new in the coolest Cloud",
"summary": "A blog post by someone real famous",
"comments": [
{"id": 1, "author": "anon", "comment": "something useful, I'm sure"},
{"id": 2, "author": "bob", "comment": "wisdom from the interwebs"},
…
{"id": 100001, "author": "jane", "comment": "and on we go ..."},
…
{"id": 1000000001, "author": "angry", "comment": "blah angry blah angry"},
…
{"id": ∞ + 1, "author": "bored", "comment": "oh man, will this ever end?"},
]
}
如果我们要对一个典型博客或内容管理系统建模,那么具有嵌入式评论的发布实体可能就如示例所示。 此示例中的问题是评论数组没有限制,这意味着任何单个发布的评论数都没有(实际)限制。 此设计可能会导致问题,因为项目的大小可以无限大,因此请避免此问题。
随着项大小的增加,大规模传输、读取和更新数据变得更加具有挑战性。
在此情况下,最好是考虑以下数据模型。
Post item:
{
"id": "1",
"name": "What's new in the coolest Cloud",
"summary": "A blog post by someone real famous",
"recentComments": [
{"id": 1, "author": "anon", "comment": "something useful, I'm sure"},
{"id": 2, "author": "bob", "comment": "wisdom from the interwebs"},
{"id": 3, "author": "jane", "comment": "....."}
]
}
Comment items:
[
{"id": 4, "postId": "1", "author": "anon", "comment": "more goodness"},
{"id": 5, "postId": "1", "author": "bob", "comment": "tails from the field"},
...
{"id": 99, "postId": "1", "author": "angry", "comment": "blah angry blah angry"},
{"id": 100, "postId": "2", "author": "anon", "comment": "yet more"},
...
{"id": 199, "postId": "2", "author": "bored", "comment": "will this ever end?"}
]
此模型的每个注释都有一个项,其中的一个属性包含 post 标识符。 这种模型使帖子能够包含任意数量的评论,并且可以高效地扩展。 如果用户想要查看的内容不止是最近的评论,则需通过传递 postId(应为评论容器的分区键)查询此容器。
另一种不适合嵌入数据的情况是,当嵌入的数据经常在多个项目之间使用并且经常变化时。
以下面的 JSON 代码段为例。
{
"id": "1",
"firstName": "Thomas",
"lastName": "Andersen",
"holdings": [
{
"numberHeld": 100,
"stock": { "symbol": "zbzb", "open": 1, "high": 2, "low": 0.5 }
},
{
"numberHeld": 50,
"stock": { "symbol": "xcxc", "open": 89, "high": 93.24, "low": 88.87 }
}
]
}
这个例子可以代表一个人的股票投资组合。 我们选择在每个投资组合文档中嵌入股票信息。 在相关数据频繁变化的环境中,嵌入频繁变化的数据意味着需要不断更新每个投资组合。 以股票交易应用程序为例,每次股票交易时,都需要更新投资组合中的每个项目。
在一天时间里股票 zbzb 可能交易成百上千次,并且数以千计的用户可能在其投资组合中具有股票 zbzb。 如果采用类似示例中的数据模型,系统每天必须多次更新数千份资产组合文档,这无法很好地扩展。
参考数据
嵌入式数据在很多情况下都可以很好运作,但在一些情况下,非规范化数据会导致更多问题而得不偿失。 所以,你可以做什么?
可以在文档数据库中创建实体之间的关系,而不仅仅是在关系数据库中创建关系。 在文档数据库中,一个项可以包含与其他文档中的数据相关的信息。 Azure Cosmos DB 并非为关系数据库中的复杂关系而设计,但可以建立项目之间的简单链接,这很有帮助。
在 JSON 中,我们使用前面的股票投资组合示例,但是这次我们引用了投资组合中的股票项目,而不是嵌入此项目。 在这种情况下,当一天当中股票项发生频繁更改时,仅有的需要更新的项就是一个股票文档。
Person document:
{
"id": "1",
"firstName": "Thomas",
"lastName": "Andersen",
"holdings": [
{ "numberHeld": 100, "stockId": 1},
{ "numberHeld": 50, "stockId": 2}
]
}
Stock documents:
{
"id": "1",
"symbol": "zbzb",
"open": 1,
"high": 2,
"low": 0.5,
"vol": 11970000,
"mkt-cap": 42000000,
"pe": 5.89
},
{
"id": "2",
"symbol": "xcxc",
"open": 89,
"high": 93.24,
"low": 88.87,
"vol": 2970200,
"mkt-cap": 1005000,
"pe": 75.82
}
此方法的一个缺点是,应用程序必须发出多个数据库请求来获取有关人员投资组合中每个股票的信息。 这种设计可以加快数据写入速度,因为更新频繁发生。 但是,它降低了数据读取或查询速度,不过对于这个系统来说,这一点并不重要。
注意
规范化的数据模型可能需要更多的往返访问服务器。
外键呢?
由于没有约束(例如外键)的概念,数据库不会验证文档之间的任何关联关系;这些链接实际上是“弱链接”。要想确保某个条目引用的数据确实存在,则需要在应用程序中执行此步骤,或者使用 Azure Cosmos DB 上的服务器端触发器或存储过程。
何时引用
通常在下列情况下使用规范化的数据模型:
- 表示“一对多”关系。
- 表示“多对多”关系。
- 相关数据频繁更改。
- 引用的数据可能没有限制。
注意
通常规范化能够提供更好的写入性能。
将关系数据存储在何处?
关系的增长将有助于确定用于存储引用的项。
让我们看看对出版商和书籍进行建模的 JSON。
Publisher document:
{
"id": "mspress",
"name": "Microsoft Press",
"books": [ 1, 2, 3, ..., 100, ..., 1000]
}
Book documents:
{"id": "1", "name": "Azure Cosmos DB 101" }
{"id": "2", "name": "Azure Cosmos DB for RDBMS Users" }
{"id": "3", "name": "Taking over the world one JSON doc at a time" }
...
{"id": "100", "name": "Learn about Azure Cosmos DB" }
...
{"id": "1000", "name": "Deep Dive into Azure Cosmos DB" }
如果每个出版社的图书数量较少且增长有限,则将图书参考信息存储在出版社项中可能很有用。 但是,如果每个出版商的书籍数量没有限制,那么此数据模型将产生可变、不断增长的数组,类似于示例中的出版商文档。
通过切换结构,可以生成一个表示相同数据的模型,但避免了包含大规模可变集合的情况。
Publisher document:
{
"id": "mspress",
"name": "Microsoft Press"
}
Book documents:
{"id": "1","name": "Azure Cosmos DB 101", "pub-id": "mspress"}
{"id": "2","name": "Azure Cosmos DB for RDBMS Users", "pub-id": "mspress"}
{"id": "3","name": "Taking over the world one JSON doc at a time", "pub-id": "mspress"}
...
{"id": "100","name": "Learn about Azure Cosmos DB", "pub-id": "mspress"}
...
{"id": "1000","name": "Deep Dive into Azure Cosmos DB", "pub-id": "mspress"}
在此示例中,发布者文档不再包含无界集合。 相反,每个书籍文档都包含对其出版商的引用。
如何对多对多关系建模?
在关系数据库中,通常使用联接表对多对多关系建模。 这些关系只是将其他表中的记录连接在一起。
可能想要使用文档复制相同内容,并生成类似以下示例的数据模型。
Author documents:
{"id": "a1", "name": "Thomas Andersen" }
{"id": "a2", "name": "William Wakefield" }
Book documents:
{"id": "b1", "name": "Azure Cosmos DB 101" }
{"id": "b2", "name": "Azure Cosmos DB for RDBMS Users" }
{"id": "b3", "name": "Taking over the world one JSON doc at a time" }
{"id": "b4", "name": "Learn about Azure Cosmos DB" }
{"id": "b5", "name": "Deep Dive into Azure Cosmos DB" }
Joining documents:
{"authorId": "a1", "bookId": "b1" }
{"authorId": "a2", "bookId": "b1" }
{"authorId": "a1", "bookId": "b2" }
{"authorId": "a1", "bookId": "b3" }
这种方法可行,但是要加载作者及其书籍,或者加载书籍及其作者,总是至少需要两次额外的数据库查询。 一次是对联接项的查询,另一个查询用来获取联接的实际项。
如果此联接只是将两个数据片段粘合在一起,那么为什么不将它完全删除? 请看下面的示例。
Author documents:
{"id": "a1", "name": "Thomas Andersen", "books": ["b1", "b2", "b3"]}
{"id": "a2", "name": "William Wakefield", "books": ["b1", "b4"]}
Book documents:
{"id": "b1", "name": "Azure Cosmos DB 101", "authors": ["a1", "a2"]}
{"id": "b2", "name": "Azure Cosmos DB for RDBMS Users", "authors": ["a1"]}
{"id": "b3", "name": "Learn about Azure Cosmos DB", "authors": ["a1"]}
{"id": "b4", "name": "Deep Dive into Azure Cosmos DB", "authors": ["a2"]}
使用此模型,你可以通过查看作者的文档轻松查看作者撰写的书籍。 还可以通过查看图书文档来了解哪些作者撰写了这本书。 无需使用单独的联接表或进行额外的查询。 通过此模型,应用程序可以更快、更简单地获取所需的数据。
混合数据模型
我们探讨了数据的嵌入(或去规范化)以及引用(或规范化)的问题。 每种方法都有其优点,同时也存在一些权衡之处。
通常不必非得非此即彼。 可以适当尝试将多种方法结合起来使用。
根据应用程序的具体使用模式和工作负载,将嵌入式数据与引用数据混合使用可能是合理的做法。 这种方法能够简化应用程序的逻辑,减少服务器往返次数,并保持良好的性能。
请考虑以下 JSON。
Author documents:
{
"id": "a1",
"firstName": "Thomas",
"lastName": "Andersen",
"countOfBooks": 3,
"books": ["b1", "b2", "b3"],
"images": [
{"thumbnail": "https://....png"}
{"profile": "https://....png"}
{"large": "https://....png"}
]
},
{
"id": "a2",
"firstName": "William",
"lastName": "Wakefield",
"countOfBooks": 1,
"books": ["b1"],
"images": [
{"thumbnail": "https://....png"}
]
}
Book documents:
{
"id": "b1",
"name": "Azure Cosmos DB 101",
"authors": [
{"id": "a1", "name": "Thomas Andersen", "thumbnailUrl": "https://....png"},
{"id": "a2", "name": "William Wakefield", "thumbnailUrl": "https://....png"}
]
},
{
"id": "b2",
"name": "Azure Cosmos DB for RDBMS Users",
"authors": [
{"id": "a1", "name": "Thomas Andersen", "thumbnailUrl": "https://....png"},
]
}
此处我们(主要)遵循了嵌入式模型,在顶层文档中嵌入其他实体的数据,但同时引用了其他数据。
如果查看书籍文档中的作者数组,会看到一些有趣的字段。 某个 id 字段是用来引用作者文档的字段,这是规范化模型中的标准做法,但是我们还使用了 name 和 thumbnailUrl。 我们可以只使用 id,让应用程序通过“链接”从相应的作者项中检索所需的其他信息。但是,由于应用程序会在每本书旁边显示作者姓名和缩略图,因此对某些作者数据进行反规范化可以减少列表中每本书的服务器往返次数。
如果作者的姓名发生了变化或者他们更换了照片,那么你需要更新他们所出版的每一本书的信息。 然而,对于这个应用来说,假设作者很少更改名字,那么这种折中的方案是可以接受的设计决策。
在这个例子中,有预先计算好的聚合值,用于在读取操作时节省高昂的处理开销。 在本例中,作者项中嵌入的一些数据为在运行时计算的数据。 每当出版了一本新书,就会创建一个书籍项并将 countOfBooks 字段设置为基于特定作者的现有书籍文档数的计算值。 这种优化对于读取频繁的系统来说是有益的,为了优化读取,我们可以对写入操作执行更多计算。
因为 Azure Cosmos DB 支持多文档事务,所以构建一个具有预先计算字段的模型是可能的。 许多 NoSQL 存储无法跨文档执行事务,正是因为该限制,所以提倡诸如“始终嵌入所有数据”的设计决策。 在 Azure Cosmos DB 中,可以使用服务器端触发器或存储过程在一个 ACID 事务中插入书籍和更新作者信息等。 现在无需将所有数据嵌入一个项,只需确保数据保持一致性。
区分不同的项类型
在某些情况下,你可能想要在同一个集合中混合使用不同的项类型;当你想要将多个相关的文档放入同一个分区时,通常可以采用这种设计选择。 例如,可将书籍和书籍评论放入同一个集合,并按 bookId 将此集合分区。 在这种情况下,通常需要向文档添加一个字段,用于标识其类型以区分它们。
Book documents:
{
"id": "b1",
"name": "Azure Cosmos DB 101",
"bookId": "b1",
"type": "book"
}
Review documents:
{
"id": "r1",
"content": "This book is awesome",
"bookId": "b1",
"type": "review"
}
{
"id": "r2",
"content": "Best book ever!",
"bookId": "b1",
"type": "review"
}
Azure Synapse Link 和 Azure Cosmos DB 分析存储的数据建模
适用于 Azure Cosmos DB 的 Azure Synapse Link 是一种云原生混合事务和分析处理 (HTAP) 功能,可用于对 Azure Cosmos DB 中的操作数据运行准实时分析。 Azure Synapse Link 在 Azure Cosmos DB 和 Azure Synapse Analytics 之间建立无缝集成。
这种集成是通过 Azure Cosmos DB 分析存储进行的。此分析存储是事务数据的列式表示形式,可实现大规模的分析,且不会对事务工作负载造成任何影响。 分析型存储使你能够在大规模数据集上运行快速且经济的查询。 无需复制数据,也无需担心减慢主数据库的速度。 为容器启用分析存储时,对数据所做的每一项更改几乎都会立即复制到分析存储中。 无需设置更改源或运行提取、转换和加载 (ETL) 作业。 系统会自动确保两个存储保持同步。
借助 Azure Synapse Link,现在可以直接从 Azure Synapse Analytics 连接到 Azure Cosmos DB 容器和访问分析存储,而不会产生任何请求单位(请求单位)成本。 Azure Synapse Analytics 目前支持具有 Synapse Apache Spark 和无服务器 SQL 池的 Azure Synapse Link。 若你拥有全局分发的 Azure Cosmos DB 帐户,为容器启用分析存储后,它将适用于该帐户的所有区域。
分析存储自动架构推理
Azure Cosmos DB 事务存储是面向行的半结构化数据,但分析存储采用列和结构化格式。 系统会使用分析存储的架构推理规则为客户自动完成这种转换。 转换过程存在以下方面的限制:最大嵌套级别数目、最大属性数目、不支持的数据类型,等等。
注意
在分析存储的上下文中,我们将以下结构视为属性:
- JSON“元素”或“由
:分隔的字符串-值对” - 由
{和}括起的 JSON 对象 - 由
[和]括起的 JSON 数组
使用以下技术可以充分减轻架构推理转换造成的影响,并充分提高分析能力。
标准化
由于 Azure Synapse Link 允许使用 T-SQL 或 Spark SQL 联接容器,因此规范化变得不那么重要了。 规范化的预期好处是:
- 减少事务存储和分析存储中的数据占用空间。
- 较小的交易。
- 减少每个文档的属性数。
- 减少数据结构的嵌套级别数。
数据中属性和层级越少,分析查询速度就越快。 它还有助于确保数据的所有部分都包含在分析存储中。 如有关自动架构推理规则的文章中所述,在分析存储中表示的级别和属性数目是有限制的。
规范化的另一个重要因素是 Azure Synapse 中的 SQL无服务器池支持最多包含 1000 列的结果集,并且公开嵌套列也计入该限制。 换言之,分析存储和 Synapse SQL无服务器池都限制为 1,000 个属性。
但是,既然非规范化是 Azure Cosmos DB 的一项重要数据建模技术,我该怎么做呢? 答案是必须为事务和分析工作负载找到适当的平衡点。
分区键
分析存储中不使用 Azure Cosmos DB 分区键 (PK)。 现在可以使用所需的任何 PK 对分析存储的副本使用分析存储自定义分区。 由于这种隔离,可为事务数据选择一个 PK 并将重点放在数据引入和点读取上,而跨分区查询可以通过 Azure Synapse Link 来完成。 请看以下示例:
在假设的全局 IoT 方案中,我们将 device id 用作良好的分区键,因为所有设备都会生成类似的数据量,从而防止出现热分区问题。 但是若要分析多个设备的数据,例如“昨天的所有数据”或“每个城市的总计”,你可能会遇到问题,因为查询是一些跨分区查询。 这些查询可能会损害事务性能,因为它们使用一部分吞吐量(以请求单位为单位)来运行。 但如果使用 Azure Synapse Link,可以运行这些分析查询而不产生请求单位成本。 分析存储列格式针对分析查询进行了优化,Azure Synapse Link 与 Azure Synapse Analytics 运行时配合使用,可提供出色的性能。
数据类型和属性名称
有关自动架构推理规则的文章列出了支持的数据类型。 虽然 Azure Synapse 的运行时可能会以不同方式处理受支持的数据类型,但不受支持的数据类型将无法在分析型存储中表示。 一个示例是:在使用遵循 ISO 8601 UTC 标准的日期/时间字符串时,Azure Synapse 中的 Spark 池会将这些列表示为 string,而 Azure Synapse 中的 SQL 无服务器池会将这些列表示为 varchar(8000)。
另一个挑战是 Azure Synapse Spark 不支持全部字符。 虽然它接受空格,但不接受冒号、重音符和逗号等字符。 假设你的项包含一个名为“First Name, Last Name”的属性。 此属性将在分析存储中表示,Synapse SQL 无服务器池也可以正常读取它。 但此属性位于分析存储中,而 Azure Synapse Spark 无法从分析存储中读取任何数据,包括所有其他属性。 总而言之,如果某个属性在其名称中使用了不受支持的字符,你就无法使用 Azure Synapse Spark。
数据平展
Azure Cosmos DB 数据顶层的每个属性都会成为分析存储中的列。 嵌套对象或数组中的属性以 JSON 格式存储在分析存储中,并保持其结构不变。 嵌套结构要求 Azure Synapse 运行时进行额外处理,以将数据转换为平面化结构,这在大数据场景中可能是一个挑战。
该项在分析存储中只有两列:id 和 contactDetails。 所有其他数据,例如 email 和 phone,都需要通过 SQL 函数进行额外处理才能单独读取。
{
"id": "1",
"contactDetails": [
{"email": "thomas@andersen.com"},
{"phone": "+1 555 555-5555"}
]
}
该项在分析存储中具有三列,id、email 以及 phone。 所有数据都可以作为列直接访问。
{
"id": "1",
"email": "thomas@andersen.com",
"phone": "+1 555 555-5555"
}
数据分层
Azure Synapse Link 允许从以下角度降低成本:
- 在你的事务数据库中运行的查询数量减少。
- 针对数据引入和点读取进行优化的 PK,减少数据占用空间、热分区方案和分区拆分。
- 由于分析生存时间 (ATTL) 与事务生存时间 (TTTL) 不相关,因此可以实现数据分层。 可在事务存储中将事务数据保留几天、几周、几个月,并在分析存储中将数据保留数年或永久保留。 分析存储列格式融合了自然数据压缩,压缩率为 50% 到 90%。 其每 GB 成本大约为事务存储实际价格的 10%。 有关当前备份限制的详细信息,请参阅分析存储概述。
- 环境中不会运行任何 ETL 作业,这意味着,无需为此类作业分配请求单位。
受控的冗余
当数据模型已存在且无法更改时,这个方法一种很好的替代方案。 当前数据模型不适用于分析存储。 这种优势之所以存在,是因为分析型存储有规则限制数据嵌套的层数以及每个文档中可以包含的属性数量。 如果数据过于复杂或字段过多,则分析存储中可能不会包含一些重要信息。 如果你也遇到这种情况,可以使用 Azure Cosmos DB 更改源将数据复制到另一个容器中,并应用所需的转换来生成 Azure Synapse Link 友好的数据模型。 请看以下示例:
场景
容器 CustomersOrdersAndItems 用于存储在线订单,包括客户和商品详细信息:帐单邮寄地址、交付地址、交付方式、交付状态、商品价格等。只表示前 1,000 个属性,关键信息不包含在分析存储中,这会阻止 Azure Synapse Link 的使用。 容器中包含 PB 量级的记录,无法更改应用程序以及为数据重新建模。
问题的另一个方面是大量数据。 分析部门经常使用数十亿行,导致他们无法使用 tttl 来删除旧数据。 由于分析需求,在事务数据库中维护整个数据历史记录迫使他们不断增加预配的请求单位,而这又会影响成本。 事务和分析工作负载同时争用相同的资源。
你可以做什么?
使用更改源的解决方案
- 工程团队决定使用 Change Feed 来填充三个新容器:
Customers、Orders和Items。 他们使用更改源来规范化和平展数据。 从数据模型中删除不必要的信息,使每个容器包含大约 100 个属性,这可以避免由于存在自动架构推理限制而导致的数据丢失。 - 这些新容器已启用分析存储,Analytics Department 使用 Synapse Analytics 读取数据。 这样可以减少请求单元的使用,因为分析查询在 Synapse Apache Spark 和无服务器 SQL 池中运行。
- 容器
CustomersOrdersAndItems现在已将生存时间 (TTL) 设置为仅将数据保留六个月,从而进一步减少了请求单位使用量,因为 Azure Cosmos DB 中每 GB 至少需要 1 个请求单位。 数据更少,请求单位更少。
要点
本文的最大收获是,在无架构的场景中,数据建模依然同样重要。
就像有多种方法可在屏幕上表示一个数据片段一样,数据的建模方法也不会只有一种。 需要了解应用程序以及它如何生成、使用和处理数据。 通过应用此处提供的准则,可以创建一个模型,以满足应用程序的即时需求。 应用程序更改时,使用无架构数据库的灵活性轻松调整和改进数据模型。