园区日常跑着一套智慧园区系统,招商、合同、账单、工单都在上面发生,数据自然沉淀下来。后来我们接了数智安全问数平台,让它用大白话问这些已经存在的经营数据,返回结论、图表、明细和来源。
这两套东西分工清楚。智慧园区系统管业务发生,业务办着数据就落库。问数平台管把数据看懂,它只读不写,原系统一个字不改,只是在外面多开一个问数入口。
接线的过程比预想麻烦。下面是我们踩过的 6 个坑,以及对应的解法。
原系统那一侧我们始终没动它,招商照录、合同照签、账单照开。问数平台是在外侧贴了一层只读接入,只进数据、不回写,原业务流程一条都没改。
两层的接法
图189 四层架构,从下到上是原系统数据层、只读接入层、问数层、展示层。数据层是原系统的库,问数层是数智安全问数平台的引擎,中间用只读接入层隔开,业务系统和问数引擎互不越界。
坑一 只读账号开错了,审批卡了两周
现象问数平台要查原系统数据,我们第一反应是把原系统的业务账号直接给它用。安全和运维一看就否了,这个账号能改能删,风险太大。
根因把能查数和能操作业务混在一起了。
解法单独开一个只读账号,只授权查询我们建的视图,禁止一切写入。
sql
-- 建只读角色,只给查询权 CREATE ROLE park_ro LOGIN PASSWORD 'strong_pwd'; GRANT CONNECT ON DATABASE park_biz TO park_ro; GRANT USAGE ON SCHEMA biz TO park_ro; -- 只授权视图,不碰基表 GRANT SELECT ON biz.v_rent_stat TO park_ro; GRANT SELECT ON biz.v_bill_summary TO park_ro; -- 显式收回写权限 REVOKE INSERT, UPDATE, DELETE, TRUNCATE ON ALL TABLES IN SCHEMA biz FROM park_ro;图191 只读账号带锁,连到原系统数据库,只给查询权。写操作在账号层面就被挡掉,不是靠应用代码自觉。
坑二 出租率算出来对不上
现象业务在报表里看出租率是 92%,问数平台一问变成 88%,两边争起来了。
根因两个系统对出租的定义不一样。原系统按有合同算,问数平台按已缴费算,分母也不同,一个用房源数一个用合同数。
解法把口径写进一处,原系统和问数平台都引用同一段定义。我们把它落成视图里的计算逻辑,谁都别自己重算。
sql
-- 统一口径 在租 = 状态生效且未退租的合同 -- 出租率 = 在租房源 / 可租房源(分母统一取房源数) CREATE VIEW biz.v_rent_stat AS SELECT b.building_id, COUNT(DISTINCT r.room_id) FILTER (WHERE r.status = 'available') AS rentable_rooms, COUNT(DISTINCT c.room_id) FILTER (WHERE c.status = 'active' AND c.end_date > CURRENT_DATE) AS rented_rooms, ROUND( COUNT(DISTINCT c.room_id) FILTER (WHERE c.status = 'active' AND c.end_date > CURRENT_DATE) * 1.0 / NULLIF( COUNT(DISTINCT r.room_id) FILTER (WHERE r.status = 'available'), 0), 4) AS rent_rate FROM biz.room r LEFT JOIN biz.contract c ON c.room_id = r.room_id;口径一致之后,两个出口的数字才对得上,业务也不用再怀疑哪边算错了。
坑三 只给一张图,业务不敢信
现象问数平台答本月收缴率 95%,业务回一句这数对吗,没人能核对。
根因回答只有结论,没有明细和来源,过程不透明。
解法每次回答必须带四件套,结论、图表、明细、来源。明细能点开看到每一笔,来源标到具体表和字段。
图192 提问进来,经过路由和查询,吐出结论、图表、明细、来源四件套。业务拿着明细去原系统勾一遍,信得过才敢用这个结果。
坑四 自然语言转的 SQL 扫全表
现象问一句去年各楼栋空置天数,跑了 40 秒,数据库直接告警。
根因问数平台直连主库,生成的 SQL 没走索引,大表全扫。
解法只读账号绑定到从库,再给高频查询建物化视图,限定扫描范围。
yaml
read_only_access: target: replica_db # 只读接从库,不碰主库 schema: biz allowed_objects: # 可查对象白名单 - v_rent_stat - v_bill_summary - v_contract_due materialized_views: # 高频查询预聚合 - mv_monthly_collection # 每月收缴率 scan_limit: max_rows_scan: 5000000 timeout_sec: 8从库扛查询,主库只管业务写入,两边不抢资源,慢查询也压下来了。
坑五 能查到不该看的字段
现象测试时发现问数平台能拉出租客的身份证号和合同金额明细,明显超范围。
根因只读账号授权的是整张视图,没做列级控制。
解法可查对象白名单加上列级脱敏,圈外的字段一律不可达。
图193 围栏圈住可查对象,圈外灰掉不可达。敏感字段在权限层就过滤掉,问数平台根本拿不到。
坑六 同样的问题每天重算
现象本月收缴率多少一天被问十几遍,每次都重新生成 SQL,时快时慢。
根因高频问法没有沉淀,引擎每次从零理解。
解法建 FewShot 样例库,把高频问法和对应查询存成模板,命中就直接复用。
样例库跑起来之后,重复问题响应快且稳,新问法也能顺手补进库里,越用越准。
六个坑一张表说清
| 坑 | 现象 | 根因 | 解法 |
|---|---|---|---|
| 只读账号 | 用业务账号被否 | 查数与操作混用 | 独立只读角色,只授权视图 |
| 口径 | 出租率对不上 | 定义各算各的 | 口径落地成视图,统一引用 |
| 可核对 | 只给图不敢信 | 回答无来源 | 结论加图表加明细加来源 |
| 性能 | 全表扫超时 | 直连主库无索引 | 接从库加物化视图加限扫描 |
| 越权 | 能看敏感字段 | 缺列级控制 | 白名单加列级脱敏 |
| 复用 | 重复生成 SQL | 高频问法无沉淀 | FewShot 样例库 |
我们留下的几条经验
- 原系统一个字不改,问数平台只在外面加入口
- 只读账号独立开,授权到视图,写权限在账号层收回
- 口径写在一处,原系统和问数平台都引用同一段
- 回答必须带明细和来源,能核对才敢用
- 接从库,别让问数压主库
- 白名单圈定可查对象,列级脱敏兜底
两套系统一个管发生一个管看懂,关系就这么简单。接线的难处不在算法,在权限、口径、可追溯这几件琐事。上面 6 个坑我们逐个填了,现在业务敢直接问,也能直接核对。
图194 六个坑串成一条复盘时间线,叉掉重来,勾掉过关。下次再接别的园区,这套流程能直接复用。