如何优化Firestore中逐个获取多文档的查询性能
Firestore 获取用户关联卡片性能优化方案
问题根源
你当前的代码是串行发起Card文档请求:遍历每个obtention文档时,逐个等待Card文档的请求返回,10条数据就会产生10次串行网络请求,耗时是单个请求的累加值,这是延迟高的核心原因。
优化方案
1. 并行发起所有Card请求(改动最小,效果显著)
使用Promise.all()将所有Card文档的获取请求并行执行,所有请求同时发送,总耗时接近单个请求的时间,而非累加。
修改后的代码:
const userReference = database.collection('user').doc(interaction.user.id); const cardsReference = database.collection('obtention').where('user', '==', userReference); const cardsSnapshot = await cardsReference.get(); // 收集所有Card文档的获取Promise const cardFetchPromises = cardsSnapshot.docs.map(doc => { const obtentionData = doc.data(); return obtentionData.card.get(); }); // 并行执行所有请求,一次性获取所有Card文档 const cards = await Promise.all(cardFetchPromises); // Rest of the code
2. 数据冗余(反规范化,极致性能)
如果并行请求仍无法满足性能需求,可以在obtention文档中冗余存储Card的常用字段(如name、file),这样无需额外请求Card集合,直接从obtention文档就能拿到所需数据。
调整后的obtention文档结构:
// obtention文档示例 { user: database.collection('user').doc('32138217391'), card: database.collection('card').doc('SCP-002'), cardName: 'The "Living" Room', cardFile: 'http://scp-es.com/scp-002' }
获取数据时直接读取冗余字段:
const userReference = database.collection('user').doc(interaction.user.id); const cardsReference = database.collection('obtention').where('user', '==', userReference); const cardsSnapshot = await cardsReference.get(); const cards = cardsSnapshot.docs.map(doc => { const data = doc.data(); return { id: data.card.id, name: data.cardName, file: data.cardFile }; }); // Rest of the code
注意:需要维护数据一致性,当Card文档更新时,要同步更新所有关联的
obtention文档,可以通过Firebase Cloud Functions触发器实现自动同步。
3. 使用批量读取API(减少网络开销)
Firestore提供getAll()方法,可以一次性批量获取多个文档引用对应的内容,底层会合并请求,进一步降低网络开销,效果和Promise.all()类似,但请求次数更少。
代码示例:
const userReference = database.collection('user').doc(interaction.user.id); const cardsReference = database.collection('obtention').where('user', '==', userReference); const cardsSnapshot = await cardsReference.get(); // 收集所有Card文档的引用 const cardReferences = cardsSnapshot.docs.map(doc => doc.data().card); // 批量获取所有Card文档 const cards = await database.getAll(...cardReferences); // Rest of the code
方案选择建议
- 优先尝试并行请求,代码改动最小,能将10条数据的耗时从7秒压缩到1秒以内(取决于单请求耗时)。
- 如果需要极致性能,再考虑数据冗余,适合卡片数据更新频率低、读取频率高的场景。
- 批量读取和并行请求性能接近,可根据编码习惯选择。
内容的提问来源于stack exchange,提问作者Sn4red
相关产品推荐
相关产品推荐

