You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firestore+Unity集成:手动修改数据后读取次数异常飙升求助

Unity Firestore 读取量异常暴增问题分析与解决方案

问题背景

在Unity集成Firestore SDK时出现异常:

  • 数据结构:users主集合下每个用户文档包含progress子集合存储玩家进度
  • 权限配置:默认仅允许写入,测试时临时开放读取权限
  • 异常现象:预期仅2次的文档读取操作,实际产生150-600次读取量;手动在Firestore后台修改数据后,读取次数随机且远超预期,但正常代码读写操作无此问题

原读取代码:

public static async Task<Dictionary<string, object>> GetDocSnapshotAsync(string collection, string doc)
{
    var result = new Dictionary<string, object>();
    var getCompleted = false;
    var documentReference = FirebaseFirestore.DefaultInstance.Collection(collection).Document(doc);
    documentReference.GetSnapshotAsync().ContinueWithOnMainThread(task =>
    {
        if (task.Result.Exists)
        {
            result = task.Result.ToDictionary();
        }

        getCompleted = true;
    });
    while (!getCompleted)
    {
        await Task.Delay(10);
    }
    return result;
}

public static async Task<Dictionary<string, object>> GetSubDocSnapshotAsync(string collection, string doc, string subCollection, string subDoc)
{
    var result = new Dictionary<string, object>();
    var getCompleted = false;
    var documentReference = FirebaseFirestore.DefaultInstance.Collection(collection).Document(doc).Collection(subCollection).Document(subDoc);
    documentReference.GetSnapshotAsync().ContinueWithOnMainThread(task =>
    {
        if (task.Result.Exists)
        {
            result = task.Result.ToDictionary();
        }

        getCompleted = true;
            
    });
    while (!getCompleted)
    {
        await Task.Delay(10);
    }
    return result;
}

可能原因

  1. 异步代码实现缺陷
    原代码使用while轮询getCompleted变量等待任务完成,存在线程安全隐患:getCompleted未标记为volatile,多线程环境下可能出现缓存一致性问题,导致循环无法及时退出,甚至重复触发快照请求。

  2. 本地缓存自动同步触发额外读取
    手动修改云端数据后,Firestore SDK会自动同步本地缓存与云端数据。如果代码中存在未取消的实时监听(如Snapshots.Subscribe),或SDK在权限开放后批量拉取之前因权限不足缓存的过期数据,会产生大量额外读取请求。

  3. 代码被意外重复调用
    若读取方法被放在Unity的Update/FixedUpdate等帧循环中,或绑定到重复触发的事件(如UI按钮重复点击回调),当云端数据变化时会触发大量重复读取。

  4. 权限规则变更后的缓存刷新
    开放读取权限后,SDK可能会重新拉取之前因权限限制无法获取的文档,导致批量读取请求被计数。

解决方案

  1. 修复异步代码写法
    替换轮询等待为直接await,避免线程安全问题和无效循环,同时简化代码逻辑:

    public static async Task<Dictionary<string, object>> GetDocSnapshotAsync(string collection, string doc)
    {
        var docRef = FirebaseFirestore.DefaultInstance.Collection(collection).Document(doc);
        var snapshot = await docRef.GetSnapshotAsync();
        return snapshot.Exists ? snapshot.ToDictionary() : new Dictionary<string, object>();
    }
    
    public static async Task<Dictionary<string, object>> GetSubDocSnapshotAsync(string collection, string doc, string subCollection, string subDoc)
    {
        var subDocRef = FirebaseFirestore.DefaultInstance.Collection(collection).Document(doc)
            .Collection(subCollection).Document(subDoc);
        var snapshot = await subDocRef.GetSnapshotAsync();
        return snapshot.Exists ? snapshot.ToDictionary() : new Dictionary<string, object>();
    }
    
  2. 排查并清理隐式监听
    检查代码中是否存在Snapshots.Subscribe或类似实时监听逻辑,确保在不需要时调用Subscribe返回的IDisposable对象的Dispose()方法取消订阅,避免数据变化时自动触发快照拉取。

  3. 验证代码调用频率
    在读取方法中添加日志输出,确认调用次数是否符合预期:

    Debug.Log($"触发读取:{collection}/{doc}");
    

    排查是否在帧循环、重复事件中意外调用了读取方法。

  4. 测试禁用本地缓存
    临时禁用Firestore本地缓存,验证是否是缓存同步导致的额外读取:

    var settings = new FirebaseFirestoreSettings
    {
        EnablePersistence = false
    };
    FirebaseFirestore.DefaultInstance.Settings = settings;
    
  5. 查看Firestore用量明细
    登录Firestore控制台,进入「用量」页面查看读取请求的来源(客户端IP、请求类型),确认是否为游戏客户端发起的请求,排除第三方服务或误操作的可能。

内容的提问来源于stack exchange,提问作者Всеволод Косарев

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 03:07:02