滚动新闻 →
密西西比州参议员科洛姆获川普公开肯定 民主党中期选举成果显现 SpaceX星舰第15次试飞突破轨道技术 机械哥斯拉首次亮相 唐元隽因涉嫌为中共搜集美国异议人士信息被纽约法院判缓刑三年 欧洲参与俄乌和谈遭分歧 战俘交换后冲突再升级 美国财长:伊朗黑客利用中国AI攻击法国超市冷藏系统 唐元隽涉非法搜集海外异议人士信息被判缓刑 双黄丑闻蔓延白宫 卢特尼克或因放水被问责 黄仁勋辞任事件引安全担忧 中共渗透手段升级 加拿大政界呼吁彻查中共海外警务据点 清华特等奖学金评选引争议 AI方向占比近全 前CIA局长之子因传播儿童色情制品被起诉 突发:新奥尔良港油轮撞上客船 多人落水 美国联邦航空总署实施全国航班停飞措施 退伍军人事务部长披露福利审批通过率高达94% 黄仁勋被美众议院三大委员会要求出席闭门听证会 法国10月通胀率突破3.7% 创近3年新高 山西男子砍伤妻岳母未被批捕 释放后勒死妻子引争议 黄仁勋辞职引台湾日本政界高度关注 唐元隽因向中共提供情报获三年缓刑 欧几里得望远镜发布首批观测数据 助力探索暗宇宙之谜 内蒙古化工厂氨气泄漏事件引争议,官方称属无毒催泪弹演练 英伟达共谍风暴升级 高阶芯片流向成焦点 西安村民因欠款问题冲击政务中心 无锡超算中心遭黑客入侵数据遭出售 网民质疑掩盖真相 Anthropic IPO超额认购六倍 加拿大各界在老兵纪念日缅怀阵亡将士并致敬军人 习近平称继承孙中山理念 学者质疑历史背离 孙中山纪念大会异常引关注 习健康状况引猜测 中国AI模型被指用于伊朗网络攻击 法国超市遭大规模破坏 雕刻大师现场展示技艺 纽约跨年水晶球亮相时代广场 Google Distributed Cloud 是什么,无法全部迁移到公有云的企业可以怎样部署 新疆库车市发生5.0级地震 乌鲁木齐民众普遍感知明显 美以海军高层会谈 土耳其卡塔尔签署防御协议 涉嫌为中共搜集情报 唐元隽纽约获三年缓刑 上海交大基因编辑实验致女童死亡 处罚仅限开除引争议 民主党参议院领袖选举引争议 范霍伦挑战舒默权威 江苏句容城管强抢餐车引摊贩冲突 中共借孙中山纪念进行统战操作 学者质疑继承论述模糊 黄乐与华为关联引调查 深圳数据中心牵出供应链疑云 京沪高铁山东段故障引争议 施工挖断电缆遭质疑

Firestore 数据模型怎么设计,关系型数据库开发人员需要改变哪些思路

发布时间: 2026-10-22 01:24:01    最后更新: 2026-11-13 16:32:34    阅读:95  约10 分钟阅读     

Firestore 数据模型怎么设计,关系型数据库开发人员需要改变哪些思路
图片说明:示意图   图片来源:Public Domain(公有领域)
Firestore 是 Google 提供的 NoSQL 文档数据库。对于长期使用 MySQL、PostgreSQL、SQL Server 或 Oracle 的开发人员来说,真正困难的地方通常不是学习几个 API,而是改变数据建模的方法。关系型数据库习惯从表、主键、外键、范式和 JOIN 出发,而 Firestore 更强调文档、集合、子集合、索引以及实际的数据访问模式。

Firestore 的基本存储单位是 document,文档属于 collection。一个文档可以包含字符串、数字、时间戳、数组以及嵌套对象,也可以在文档下面建立 subcollection。与关系型数据库不同,Firestore 是 schemaless 的,同一个 collection 中的文档可以拥有不同字段,但为了查询和应用逻辑保持稳定,实际项目仍然应该尽量保持字段名称和数据类型的一致性。

因此,关系型数据库开发人员进入 Firestore 后首先需要改变的,是“先设计表,再考虑查询”的习惯。Firestore 更适合从“这个业务页面到底需要读取什么数据”开始设计。例如一个电商订单页面可能需要同时显示订单基本信息、客户名称、商品摘要和配送状态。如果这些信息每次都需要通过多个关系表 JOIN 才能得到,那么在 Firestore 中就应该重新考虑数据结构,而不是机械地把原来的几张 SQL 表逐张转换成 collection。

例如用户数据可以设计成:

{
"name": "张三",
"address": {
"city": "上海",
"zip": "200000"
}
}

如果设备数量非常少,而且读取用户资料时总是需要同时显示设备信息,可以把设备作为数组保存。但如果设备数量不断增加、设备独立更新,或者需要按照设备状态、型号和更新时间单独查询,那么把设备全部塞进用户文档就不是一个好的长期设计。此时更适合使用:

users/{userId}/devices/{deviceId}

这种 subcollection 结构。

这体现了 Firestore 与关系型数据库最重要的区别之一:不是所有“关系”都应该被转换成一张独立关系表,也不是所有相关数据都应该塞进一个巨大文档。真正需要考虑的是数据是否经常一起读取、是否独立更新、数量是否会增长以及是否需要单独查询。

反规范化在 Firestore 中非常常见。例如订单文档可以保存 customerId,同时保存结算时使用的客户名称。这样订单列表就不必为了显示客户名称而额外读取用户文档。这里的数据重复并不一定是设计错误,因为它可能换来更简单的读取路径。

但反规范化也会产生同步问题。如果客户名称发生变化,而数千个订单文档中都保存着旧名称,那么应用就需要决定是否批量更新这些历史数据,还是明确规定订单中的客户名称属于交易发生时的快照。后者往往反而更合理,因为订单历史本来就不应该随着客户资料变化而被重新改写。

因此,Firestore 的“数据冗余”不能简单理解为“越少越好”。关系型数据库通常强调规范化以减少重复,而 Firestore 更强调针对读取模式进行合理的数据组织。数据重复是否值得,最终要看读取成本、写入成本、数据一致性要求以及业务语义。

多对多关系同样需要改变思路。例如用户关注用户的社交关系,如果一个用户只有几十个关注对象,可以考虑数组;但如果一个用户可能拥有数千甚至数万条关系,就不应该把所有关系无限堆积在一个用户文档里。可以建立独立的关系 collection,例如:

follows/{followId}

其中保存:

{
"followerId": "userA",
"followedId": "userB",
"createdAt": "..."
}

如果业务同时需要查询“我关注了谁”和“谁关注了我”,就需要针对这两种访问方式设计相应字段和索引,而不是期待 Firestore 像 SQL 数据库一样临时执行 JOIN。

这也是 Firestore 查询设计的核心。Firestore 没有关系型数据库意义上的 JOIN,查询主要围绕 collection、document、where 条件、排序、limit 和 cursor 展开。官方文档也明确支持组合过滤和排序,并通过索引执行查询。

因此,开发人员应该先列出实际查询,例如“查询某个用户最近30天的订单”“查询某个城市中处于配送状态的订单”“查询某个设备最近100条日志”,然后反过来设计字段和索引。

分页尤其如此。不要把关系型数据库中的 OFFSET 100000 思维原封不动搬过来。Firestore 支持 query cursor,可以利用 startAt()、startAfter() 等方式从上一次查询的位置继续读取。典型做法是第一次读取一批文档,保存最后一个文档作为下一页的 cursor,然后继续查询。

索引也应该从实际查询出发。Firestore 的查询依赖索引,复杂查询可能需要 composite index。开发人员不应该简单地为所有字段建立大量组合索引,而应该根据真实查询模式设计索引。当前 Firestore 的索引配额也远不是“一个索引最多5个字段”这么简单,数据库级 composite index 配额取决于当前数据库配置和计费状态。

另一个经常被关系型数据库开发人员误解的问题是事务。

Firestore 并不是简单的“最终一致性数据库”。Google 当前官方文档明确说明 Cloud Firestore 提供 strong consistency,并且事务具有 serializable isolation。事务中的读取和写入具有原子性,如果并发修改导致数据竞争,Firestore 可以重新执行事务,直到成功或者因为竞争等原因失败。

因此,真正需要改变的不是“从强一致性转向最终一致性”,而是理解 Firestore 的事务边界和数据竞争机制。事务适合用于“读取当前状态,然后根据这个状态决定写入结果”的场景。例如账户余额、库存数量或者需要避免并发覆盖的状态更新,都可能需要事务。

同时,不能把事务当成一个可以无限扩大的 SQL transaction。Firestore 事务存在请求大小、时间和其他资源限制。当前官方限制包括单次 API 请求最大10 MiB,事务最长270秒,并且60秒没有活动会触发空闲超时;具体操作还受到字段转换等限制。

事务还可能因为数据竞争而自动重试。因此事务函数不能包含不可重复执行的外部副作用。例如不要在事务函数内部直接发送一封邮件、扣除外部支付账户或者调用一个不可幂等的第三方 API,然后假定事务只会执行一次。Firestore 官方文档也明确提醒,事务函数可能因为并发修改而运行多次。

对于关系型数据库开发人员来说,这一点非常重要。SQL 世界中经常把业务逻辑包在一个 transaction 里,然后按照顺序执行大量操作;Firestore 更适合把真正需要原子性的状态变化缩小到明确的事务边界,其余工作通过事件、任务队列或幂等的异步处理完成。

Firestore 的另一个设计重点是文档大小和增长方式。一个文档并不是无限大的容器,因此不能把一个不断增长的日志列表、聊天记录或者订单历史全部放进某个用户文档。数量不断增长的数据通常应该拆成 collection 或 subcollection,使每个文档保持相对稳定。

嵌套数据也不是越深越好。Firestore 支持 nested maps 和 arrays,但存在字段深度限制,目前最大字段深度为20层。这个限制并不意味着“所有项目都应该保持2至3层”,真正的工程原则应该是让数据结构围绕业务访问路径保持清晰,避免形成巨大、频繁修改而且难以独立查询的文档。

安全模型也是从 SQL 数据库迁移到 Firestore 时必须重新理解的部分。客户端直接访问 Firestore 时,开发人员通常通过 Firebase Authentication 配合 Firestore Security Rules 控制访问。Rules 不应该被当成传统数据库中的一层简单 WHERE 条件,而应该根据用户身份、文档路径和业务状态设计访问控制。对于事务和批量写入,Security Rules 还有额外的文档访问调用限制,因此复杂规则也可能成为系统设计的一部分。

最终,关系型数据库开发人员真正需要改变的思维可以概括为几个问题:这个数据最常见的读取方式是什么?哪些字段应该一起读取?哪些数据会独立增长?哪些关系需要单独查询?哪些数据可以合理冗余?哪些状态必须通过事务保持原子性?哪些操作可以异步化?

如果把 MySQL 的表直接一张一张搬成 Firestore collection,通常只是把关系型数据库换了一个外壳。真正的 Firestore 设计应该从业务访问模式重新开始。

关系型数据库擅长表达复杂关系和通过 JOIN 临时组合数据,而 Firestore 更强调围绕访问路径组织文档,并利用索引、冗余、subcollection 和事务完成高频业务操作。两种数据库没有简单的先进与落后之分,关键是数据模型是否与应用的实际工作方式匹配。对于关系型数据库开发人员来说,最大的转变也正是从“数据之间是什么关系”进一步走向“应用究竟怎样读取和修改这些数据”。
本文作者
程越(Kevin Cheng)
IT与人工智能技术资深编辑

喜欢这篇报道?

使用下面的功能,方便以后继续阅读和分享 MNewsTV

设为 Google 新闻首选来源 让 Google 新闻优先显示 MNewsTV 的最新报道 ›
★ 我的收藏 查看已经收藏的文章
关于文章收藏 收藏不需要注册帐号,收藏信息仅保存在当前浏览器中。 删除收藏请进入「我的收藏」进行管理。
分享这篇报道

捐助(Paypal): https://www.paypal.me/observeccp
订阅中国观察电报 Telegram : https://t.me/s/ObserveCCP