在 BigQuery 中对导出的数据运行 SQL 查询

Crashlytics 和(可选)Firebase 会话数据导出到 BigQuery 后,您就可以开始使用这些数据了:

  • 使用 SQL 查询分析数据
    您可以对 Crashlytics 数据运行查询,以生成自定义报告和摘要。由于 Firebase 控制台的 Crashlytics 信息中心内不提供这类自定义报告,因此这些报告可以补充您对崩溃数据的分析和理解。请参阅本页面后面的示例查询集合。

  • 联接来自不同数据集的数据
    例如,如果您在设置 Crashlytics 数据导出时选择导出 Firebase 会话数据,则可以更好地了解“未遇到崩溃问题的用户数”和“未发生崩溃问题的会话数”(请参阅查询示例)。 此外,您还可以从各种 Firebase 产品(例如 Performance Monitoring)或从 Google Analytics 导出数据,然后在 BigQuery 中将这些数据与 Crashlytics 数据联接起来并进行分析。

  • 创建视图
    您可以使用 BigQuery 界面创建“视图”,它是由 SQL 查询定义的虚拟表。如需详细了解不同类型的视图及其创建方法,请参阅 BigQuery 文档

如需详细了解数据集架构,请参阅BigQuery 中导出数据的数据集架构。

了解 BigQuery SQL

Crashlytics 数据的查询示例

本部分提供了一些示例情况和示例查询,展示了如何将 BigQuery SQL 与导出的 Crashlytics 数据和 Firebase 会话数据搭配使用。

示例 1:使用 Firebase 会话数据计算“未遇到崩溃问题”指标

在最新版本中,您对应用进行了重大改版,以解决关键用户历程中的崩溃问题。您收到了用户的好评,但希望获得定量证据来证明您的应用比以前更稳定。

“未遇到崩溃问题”指标可帮助您获取此信息。这些指标是重要的衡量标准,可帮助您了解应用的总体健康状况。借助 Firebase 会话数据和 Crashlytics 事件,您可以通过基本查询计算这些指标。

以下是 Android 应用的示例查询。对于 iOS 应用,请使用其软件包 ID 和 IOS(而不是软件包名称和 ANDROID)。

特定版本的未遇到崩溃问题的用户数

SELECT
  TIMESTAMP_TRUNC(crashlytics.event_timestamp,DAY) AS event_date,
  (1 - (COUNT (DISTINCT installation_uuid) / COUNT (DISTINCT instance_id))) AS CFU
FROM
  `PROJECT_ID.firebase_sessions.PACKAGE_NAME_ANDROID` AS sessions
LEFT JOIN
  `PROJECT_ID.firebase_crashlytics.PACKAGE_NAME_ANDROID` AS crashlytics
ON
  TIMESTAMP_TRUNC(sessions.event_timestamp,DAY) = TIMESTAMP_TRUNC(crashlytics.event_timestamp,DAY)
WHERE
  crashlytics.error_type="FATAL"
  AND crashlytics.application.display_version="APP_VERSION"
  AND sessions.application.display_version = "APP_VERSION"
GROUP BY
  event_date
ORDER BY
  event_date

过去一周(过去 168 小时)未发生崩溃问题的会话

SELECT
  TIMESTAMP_TRUNC(crashlytics.event_timestamp,DAY) AS event_date,
  (1 - (COUNT (DISTINCT crashlytics.firebase_session_id) / COUNT (DISTINCT sessions.session_id))) AS CFS
FROM
  `PROJECT_ID.firebase_sessions.PACKAGE_NAME_ANDROID` AS sessions
LEFT JOIN
  `PROJECT_ID.firebase_crashlytics.PACKAGE_NAME_ANDROID` AS crashlytics
ON
  TIMESTAMP_TRUNC(sessions.event_timestamp,DAY) = TIMESTAMP_TRUNC(crashlytics.event_timestamp,DAY)
WHERE
  crashlytics.error_type="FATAL" AND _PARTITIONTIME >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 168 HOUR)
  AND _PARTITIONTIME < CURRENT_TIMESTAMP()
GROUP BY
  event_date
ORDER BY
  event_date

示例 2:每天的崩溃次数

在努力解决尽可能多的 bug 之后,您认为自己的团队终于做好了准备,可以推出全新的照片共享应用。在推出之前,您想检查一下过去一个月内每天的崩溃次数,以确保这次大规模的纠错让应用的运行更加稳定了。

以下是 Android 应用的示例查询。对于 iOS 应用,请使用其软件包 ID 和 IOS(而不是软件包名称和 ANDROID)。

SELECT
  COUNT(DISTINCT event_id) AS number_of_crashes,
  FORMAT_TIMESTAMP("%F", event_timestamp) AS date_of_crashes
FROM
 `PROJECT_ID.firebase_crashlytics.PACKAGE_NAME_ANDROID`
GROUP BY
  date_of_crashes
ORDER BY
  date_of_crashes DESC
LIMIT 30;

示例 3:查找最普遍的崩溃

为了适当排定生产计划的优先级,您需要找出应用中 10 个最普遍的崩溃。您可以生成一个查询,以提供相关数据。

以下是 Android 应用的示例查询。对于 iOS 应用,请使用其软件包 ID 和 IOS(而不是软件包名称和 ANDROID)。

SELECT
  DISTINCT issue_id,
  COUNT(DISTINCT event_id) AS number_of_crashes,
  COUNT(DISTINCT installation_uuid) AS number_of_impacted_user,
  blame_frame.file,
  blame_frame.line
FROM
  `PROJECT_ID.firebase_crashlytics.PACKAGE_NAME_ANDROID`
WHERE
  event_timestamp >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(),INTERVAL 168 HOUR)
  AND event_timestamp < CURRENT_TIMESTAMP()
GROUP BY
  issue_id,
  blame_frame.file,
  blame_frame.line
ORDER BY
  number_of_crashes DESC
LIMIT 10;

示例 4:10 大易崩溃设备

秋季是新手机的发布季!贵公司知道,这也意味着又到了解决新设备特有的问题的季节,尤其是 Android 设备。为了针对很可能出现的兼容性问题而未雨绸缪,您编写了一个查询,可以识别过去一周(168 小时)里出现最多崩溃的 10 款设备。

以下是 Android 应用的示例查询。对于 iOS 应用,请使用其软件包 ID 和 IOS(而不是软件包名称和 ANDROID)。

SELECT
  device.model,
COUNT(DISTINCT event_id) AS number_of_crashes
FROM
  `PROJECT_ID.firebase_crashlytics.PACKAGE_NAME_ANDROID`
WHERE
  event_timestamp >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 168 HOUR)
  AND event_timestamp < CURRENT_TIMESTAMP()
GROUP BY
  device.model
ORDER BY
  number_of_crashes DESC
LIMIT 10;

示例 5:按自定义键过滤

您是游戏开发者,想知道游戏崩溃次数最频繁的是哪个关卡。

为了帮助跟踪该统计信息,您可以设置一个名为 current_level 的自定义 Crashlytics 键(iOS+ | Android | Flutter | Unity),并在用户每次达到新级别时更新该键。

Swift

Crashlytics.sharedInstance().setIntValue(3, forKey: "current_level");

Objective-C

CrashlyticsKit setIntValue:3 forKey:@"current_level";

Java

Crashlytics.setInt("current_level", 3);

在导出到 BigQuery 的数据中使用该键,您可以编写一个查询来报告与各个崩溃事件相关联的 current_level 值的分布情况。

以下是 Android 应用的示例查询。对于 iOS 应用,请使用其软件包 ID 和 IOS(而不是软件包名称和 ANDROID)。

SELECT
COUNT(DISTINCT event_id) AS num_of_crashes,
  value
FROM
  `PROJECT_ID.firebase_crashlytics.PACKAGE_NAME_ANDROID`
UNNEST(custom_keys)
WHERE
  key = "current_level"
GROUP BY
  key,
  value
ORDER BY
  num_of_crashes DESC

示例 6:提取用户 ID

您有一个处于抢先体验阶段的 Android 应用。该应用的大多数用户都很喜欢它,但有三位用户遇到了异常数量的崩溃。为了确定该问题的根源,您编写了一个查询,按照用户 ID 拉取这些用户的所有崩溃事件。

以下是 Android 应用的示例查询。对于 iOS 应用,请使用其软件包 ID 和 IOS(而不是软件包名称和 ANDROID)。

SELECT *
FROM
  `PROJECT_ID.firebase_crashlytics.PACKAGE_NAME_ANDROID`
WHERE
  user.id IN ("USER_ID_1", "USER_ID_2", "USER_ID_3")
ORDER BY
  user.id
 

示例 7:查找面临特定崩溃问题的所有用户

您的团队向一组 Beta 版测试人员发布的版本中包含一个严重 bug。您的团队可以使用上面“查找最普遍的崩溃”示例中的查询来识别这一特定崩溃问题的 ID。现在,您的团队想要运行查询来提取受此崩溃影响的应用用户列表。

以下是 Android 应用的示例查询。对于 iOS 应用,请使用其软件包 ID 和 IOS(而不是软件包名称和 ANDROID)。

SELECT user.id as user_id
FROM
  `PROJECT_ID.firebase_crashlytics.PACKAGE_NAME_ANDROID`
WHERE
  issue_id = "ISSUE_ID"
  AND application.display_version = "APP_VERSION"
  AND user.id != ""
ORDER BY
  user.id;

示例 8:受崩溃问题影响的用户数量,按国家/地区细分

您的团队在发布新版本期间发现了一个严重 bug。您可以使用上面“查找最普遍的崩溃”示例中的查询来识别特定崩溃问题的 ID。您的团队现在想要确认该崩溃是否已蔓延至全球不同国家/地区的用户。

为了编写此查询,您的团队将需要执行以下操作:

  1. 启用将 Google Analytics 数据导出到 BigQuery 的功能。请参阅将项目数据导出到 BigQuery

  2. 更新应用以将用户 ID 传递到 Google Analytics SDK 和 Crashlytics SDK。

    Swift

    Crashlytics.sharedInstance().setUserIdentifier("123456789");
    Analytics.setUserID("123456789");
    

    Objective-C

    CrashlyticsKit setUserIdentifier:@"123456789";
    FIRAnalytics setUserID:@"12345678 9";
    

    Java

    Crashlytics.setUserIdentifier("123456789");
    mFirebaseAnalytics.setUserId("123456789");
    
  3. 编写一个查询,通过用户 ID 字段将 Google Analytics 数据集中的事件与 Crashlytics 数据集中的崩溃联接:

    以下是 Android 应用的示例查询。对于 iOS 应用,请使用其软件包 ID 和 IOS(而不是软件包名称和 ANDROID)。

    SELECT DISTINCT c.issue_id, a.geo.country, COUNT(DISTINCT c.user.id) as num_users_impacted
    FROM `PROJECT_ID.firebase_crashlytics.PACKAGE_NAME_ANDROID` c
    INNER JOIN  `PROJECT_ID.analytics_TABLE_NAME.events_*` a on c.user.id = a.user_id
    WHERE
      c.issue_id = "ISSUE_ID"
      AND a._TABLE_SUFFIX BETWEEN '20190101'
      AND '20200101'
    GROUP BY
      c.issue_id,
      a.geo.country,
      c.user.id

示例 9:今天到现在为止的 5 大问题

以下是 Android 应用的示例查询。对于 iOS 应用,请使用其软件包 ID 和 IOS(而不是软件包名称和 ANDROID)。

SELECT
  issue_id,
  COUNT(DISTINCT event_id) AS events
FROM
  `PROJECT_ID.firebase_crashlytics.PACKAGE_NAME_ANDROID_REALTIME`
WHERE
  DATE(event_timestamp) = CURRENT_DATE()
GROUP BY
  issue_id
ORDER BY
  events DESC
LIMIT
  5;

示例 10:自 DATE 起至今(包括今天)的 5 大问题

您还可以将批量表和实时表与拼接查询结合使用,以便将实时信息添加到可靠的批量数据中。由于 event_id 是主键,因此您可以使用 DISTINCT event_id 对两个表中的任何常见事件进行重复数据删除。

以下是 Android 应用的示例查询。对于 iOS 应用,请使用其软件包 ID 和 IOS(而不是软件包名称和 ANDROID)。

SELECT
  issue_id,
  COUNT(DISTINCT event_id) AS events
FROM (
  SELECT
    issue_id,
    event_id,
    event_timestamp
  FROM
    `PROJECT_ID.firebase_crashlytics.PACKAGE_NAME_ANDROID_REALTIME`
  UNION ALL
  SELECT
    issue_id,
    event_id,
    event_timestamp
  FROM
    `PROJECT_ID.firebase_crashlytics.PACKAGE_NAME_ANDROID`)
WHERE
  event_timestamp >= PARSE_TIMESTAMP("%Y_%m_%d", "YYYY_MM_DD")
GROUP BY
  issue_id
ORDER BY
  events DESC
LIMIT
  5;

后续步骤