风控规则怎么用 MySQL 做实时判断
MySQL 本身不提供“风控引擎”能力,但可以用它承载规则元数据 + 执行轻量级实时校验。关键不是写复杂逻辑,而是把规则拆成可 SQL 化的条件,比如单表查询、简单 JOIN、函数计算。
典型做法是:规则配置存表(如
risk_rule),运行时拼接或预编译成 WHERE 条件,用
SELECT COUNT(*)或
EXISTS快速返回是否触发。 规则字段建议包含:
rule_code、
condition_sql(如
"amount > 5000 AND user_level = 'VIP'")、
trigger_action(如
"block"或
"review") 避免在
condition_sql中写子查询或跨库引用,MySQL 8.0+ 支持 PREPARE,但高并发下动态拼 SQL 易引发注入和性能抖动,更稳的方式是预定义规则模板 + 参数绑定 实际执行时,用应用层把业务参数(如
user_id=123、
amount=6200)代入模板生成安全 WHERE,再查
risk_rule表匹配生效规则
为什么别在 MySQL 里写存储过程做风控决策
存储过程看似能封装逻辑,但风控规则需要频繁变更、灰度、回滚——而 ALTER PROCEDURE 在生产库上操作成本高、不可版本化、难以审计。
更严重的是:存储过程内做多表 JOIN + 函数调用(如
DATE_SUB(NOW(), INTERVAL 1 HOUR))会显著拖慢事务响应,尤其在支付/登录等主链路中。 MySQL 的执行计划对动态条件不友好,
IF/
CASE嵌套深了容易跳过索引 无法和外部风控系统(如 Redis 实时画像、Flink 流特征)联动,规则变成孤岛 测试困难:你没法给一个存储过程写单元测试,但可以对一条 SELECT 语句断言结果
如何让规则支持“近 N 分钟频次限制”这类时间窗口逻辑
纯 MySQL 实现滑动窗口有代价,但固定窗口(如“每小时最多 5 次”)可以直接用聚合查询落地。
示例:检查用户
user_id = 1001在过去 1 小时内是否发起超 5 笔订单
SELECT COUNT(*) >= 5 FROM order_log WHERE user_id = 1001 AND create_time >= DATE_SUB(NOW(), INTERVAL 1 HOUR);必须确保
create_time有索引,且类型为
DATETIME或
TIMESTAMP(别用字符串存时间) 如果精度要到秒级且 QPS 高,考虑加覆盖索引,例如
INDEX idx_uid_time (user_id, create_time)注意时区:MySQL 的
NOW()返回 server 时区时间,若业务按 UTC 统一计数,需用
UTC_TIMESTAMP()并确保字段也存 UTC
规则上线前最容易被忽略的三个点
不是语法对不对,而是边界是否真实覆盖。
NULL值陷阱:比如规则写
status != 'success',但
status允许为 NULL,这条记录会被跳过——应显式写成
status IS NULL OR status != 'success'字符集隐式转换:当
user_id是
VARCHAR但传入数字参数(如
WHERE user_id = 123),MySQL 可能放弃索引,改用全表扫描 未考虑事务隔离级别:若风控查询和业务写入在同一个事务里,且用了
READ COMMITTED,可能查不到刚插入但未提交的日志记录,导致漏判
真正卡住上线的,往往不是“能不能写出来”,而是“有没有跑进所有分支路径里”。
