第一章:审计数据源概览——交易系统的“家底”你得摸清

做交易审计,说白了就是跟数据打交道。我干了这么多年审计,最深的体会就是:数据源搞不清楚,后面全是白搭。你想想看,连订单存哪儿、流水怎么流转都不清楚,怎么去查异常交易?

这一章,咱们就把交易系统的“家底”翻一翻。我会从三个核心表结构讲起,再带你看看数据仓库怎么分层,最后聊聊数据血缘追踪——嗯,这些都是我日常审计工作中反复用到的东西。

1.1 交易系统核心表结构

交易系统再复杂,核心表也就那么几张。我个人习惯,拿到一个新系统,先看这三张表:

1.1.1 订单表(Order Table)

订单表是交易的“户口本”。每笔交易从创建到完成,状态变化都记录在这里。我在项目中遇到过,有些系统把订单表和流水表混在一起,结果审计时查个历史状态要关联七八张表,那叫一个痛苦。

典型的订单表结构长这样:

CREATE TABLE t_order (
    order_id        BIGINT PRIMARY KEY,      -- 订单ID
    user_id         BIGINT,                   -- 用户ID
    product_id      BIGINT,                   -- 商品ID
    order_amount    DECIMAL(18,2),            -- 订单金额
    order_status    TINYINT,                  -- 订单状态:0-待支付 1-已支付 2-已取消
    create_time     DATETIME,                 -- 创建时间
    update_time     DATETIME                  -- 更新时间
);
审计关注点:订单状态变更时间戳。我曾经查过一笔异常交易,就是发现订单的“已支付”时间比“创建时间”还早了几秒——明显是数据篡改。

1.1.2 流水表(Transaction Flow Table)

流水表是交易的“日记本”。每一笔资金变动,都会在这里留下记录。说白了,订单表告诉你“发生了什么”,流水表告诉你“钱怎么走的”。

CREATE TABLE t_trans_flow (
    flow_id         BIGINT PRIMARY KEY,      -- 流水ID
    order_id        BIGINT,                   -- 关联订单ID
    from_account    VARCHAR(32),              -- 付款账户
    to_account      VARCHAR(32),              -- 收款账户
    amount          DECIMAL(18,2),            -- 交易金额
    flow_type       TINYINT,                  -- 流水类型:1-支付 2-退款 3-提现
    flow_status     TINYINT,                  -- 流水状态:0-处理中 1-成功 2-失败
    trans_time      DATETIME                  -- 交易时间
);
避坑指南:我曾经遇到过一个系统,流水表的金额字段用了FLOAT类型,结果对账时总是差几分钱。记住:金额字段必须用DECIMAL,别问我为什么,血的教训。

1.1.3 账户表(Account Table)

账户表是用户的“钱包”。余额、冻结金额、可用余额,都在这里。审计时,我们经常要核对:账户余额 = 所有订单金额之和 - 所有流水金额之和。如果对不上,那就有问题了。

CREATE TABLE t_account (
    account_id      VARCHAR(32) PRIMARY KEY,  -- 账户ID
    user_id         BIGINT,                   -- 用户ID
    balance         DECIMAL(18,2),            -- 账户余额
    frozen_amount   DECIMAL(18,2),            -- 冻结金额
    available_bal   DECIMAL(18,2),            -- 可用余额
    version         INT                       -- 乐观锁版本号
);
核心公式:可用余额 = 账户余额 - 冻结金额。这个等式如果不等,要么是代码bug,要么是有人在搞鬼。

1.2 数据仓库分层逻辑

做审计数据分析,不能直接查业务库——你想想看,万一一个慢查询把业务库拖垮了,那可不是闹着玩的。所以,我们需要数据仓库。我习惯用四层结构:

数据仓库分层架构图 ODS 层(操作数据存储) 原始数据:订单表、流水表、账户表(与业务库结构一致) DWD 层(明细数据层) 数据清洗、去重、格式统一、维度退化 DWS 层(汇总数据层) 按用户、时间、产品等维度汇总:日交易额、月活跃用户数 ADS 层(应用数据层) 审计报表、异常交易预警、监管报送数据

这四层各有各的用处:

  • ODS层:原封不动地把业务库数据搬过来。我建议只做增量同步,别全量——全量同步一次,够你等半天的。
  • DWD层:清洗、去重、格式统一。举个例子,业务库的订单状态可能是“1、2、3”,DWD层我会转成“已支付、已发货、已完成”。
  • DWS层:按维度汇总。审计时查“某用户本月交易总额”,直接从这层拿,秒出结果。
  • ADS层:面向具体应用。比如监管报表、异常交易预警,都是在这层做的。
我的经验:审计查询尽量走DWS层。ODS层数据量大,DWD层结构复杂,只有DWS层是“拎包入住”的。当然,查明细时还得回DWD层。

1.3 数据血缘关系追踪

数据血缘,说白了就是“数据从哪里来,到哪里去”。做审计时,这个特别重要。你想想看,如果发现一个报表数据不对,你得能追溯到源头——是业务库的问题,还是ETL脚本写错了?

我常用的血缘追踪方式有三种:

追踪方式 适用场景 优点 缺点
字段级血缘 定位具体字段来源 精确到字段,定位快 维护成本高
表级血缘 了解数据流转链路 简单直观 粒度不够细
任务级血缘 排查ETL任务问题 能定位到具体任务 依赖调度系统

举个例子。有一次我发现ADS层的“日交易额报表”数据不对,比实际少了200万。我顺着血缘关系往上查:

  1. ADS层的数据来自DWS层的“日交易汇总表”
  2. DWS层的数据来自DWD层的“交易明细表”
  3. DWD层的数据来自ODS层的“流水表”
  4. ODS层的数据来自业务库的“t_trans_flow”表

最后发现,是ODS到DWD的ETL脚本里,有个过滤条件写错了——把退款流水给过滤掉了。嗯,这种问题,没有血缘关系追踪,你根本不知道从哪儿查起。

避坑指南:我曾经接手过一个项目,数据血缘全靠“人肉记忆”——老员工走了,新来的根本不知道数据怎么流转的。所以,一定要用工具做血缘管理,比如Atlas、DataHub都行,别省这个钱。

小结

这一章咱们聊了三个核心点:

  • 核心表结构:订单表、流水表、账户表,三张表构成了交易系统的骨架
  • 数据仓库分层:ODS→DWD→DWS→ADS,每一层都有它的使命
  • 数据血缘追踪:没有血缘关系,审计就是盲人摸象

做审计,数据源就是你的“弹药库”。弹药库摸清楚了,后面查异常交易、做合规分析,才能有的放矢。下一章,咱们聊聊数据质量的那些坑——嗯,这个话题,我能讲三天三夜。


公众号:蓝海资料掘金营,微信deep3321