问题现象
普通 SQL 正常,stg 环境没发现异常。但生产环境用户反馈:超长 SQL(超过 1MB)会触发 400 报错。
恰好生产环境的用户有很多那种业务逻辑复杂、拼接出来的超长 SQL。
排查过程
第一步是对比。把报错的 SQL 和不报错的 SQL 摆在一起看,唯一的共同点就是——长。
短 SQL 跑得好好的,长到一定长度就 400。这不是 SQL 语法问题,是传输层的问题。
根因
查到最后,原因是这样的:
- 安全合规要求,把普通的
Statement升级为PreparedStatement。因为普通 Statement 有 SQL 注入风险,安全团队要求整改。 - Presto 驱动版本太低,低版本的 Presto JDBC 驱动对
PreparedStatement的支持不完善,特别是对超长 SQL 的处理有 bug。 - 服务端 Presto 没有同步升级。原因很简单——影响太大,涉及的下游服务和业务太多,不敢动。
所以就出现了一个尴尬的局面:客户端驱动升级了(为了安全),服务端没升级(为了稳定),两边版本不一致,超长 SQL 直接 400。
解决方案
还原升级。
把客户端驱动退回到兼容当前服务端的版本。安全问题用其他方式规避(比如在应用层做参数化查询、输入校验等)。
这不是最优解,但在"安全"和"可用"之间,先保可用。
避坑建议
1. 灰度环境重点覆盖验证
stg 环境为什么没发现?因为测试用的 SQL 都是短的。灰度环境应该重点覆盖边界场景:
- 超长 SQL(1MB+)
- 特殊字符
- 高并发场景
2. 客户端和服务端版本要对齐
升级驱动前,先确认服务端版本兼容性。不要客户端升了、服务端没升,两边版本不一致是定时炸弹。
3. 安全整改要评估影响面
安全团队要求升级 Statement → PreparedStatement,这个决策本身没问题。但执行前应该评估:
- 当前 Presto 驱动版本是否支持
- 服务端是否需要同步升级
- 影响的业务范围
4. SQL 长度监控
在应用层加 SQL 长度监控和告警。不是所有用户都会写短 SQL,业务复杂度上去了,SQL 就会变长。提前发现比线上报错强。
总结
这个事故的教训:
- 版本对齐比什么都重要,客户端和服务端不要各升各的
- stg 测试要覆盖生产真实场景,不能只测"正常路径"
- 安全和稳定要平衡,不能为了安全把生产搞挂了
相关技术:Presto JDBC、PreparedStatement、SQL 注入防护