当前位置: 首页 > news >正文

我用AI生成的SQL,差点在生产库上跑了一整夜

我用AI生成的SQL,差点在生产库上跑了一整夜

目录

  • 凌晨的告警短信
  • 那段"看起来没问题"的SQL
  • EXPLAIN输出告诉我真相
  • 为什么AI不关心你的索引
  • 给AI加规则后重新生成
  • 我现在怎么用AI写SQL

凌晨的告警短信

那天凌晨两点,手机连续收到四条阿里云RDS告警:"CPU使用率超过90%","活跃连接数超过200","慢查询阈值触发"。我打开DMS连上去一看,show processlist里躺着一条SQL,Time列显示已经跑了23分钟,state是Sending data

这条SQL是我下午让AI生成的。

业务场景不复杂:运营要一个数据报表,统计最近30天各商品类目的订单转化率。我懒得手写这条跨五张表的统计查询,就把需求描述贴给了AI:"写一条MySQL查询,统计近30天每个商品类目的订单转化率,需要关联用户表、商品表、类目表、订单表和订单明细表,按转化率降序排列。"

AI很快给出了结果,我在测试环境跑了一下,数据量小的时候返回很快,看起来没问题。代码评审的时候也没人觉得有毛病——五表JOIN在报表场景太常见了。

那段"看起来没问题"的SQL

AI产出的SQL大概是这个结构(脱敏后):

sql SELECT c.category_name, c.category_id, COUNT(DISTINCT o.order_id) AS total_orders, COUNT(DISTINCT oi.order_id) AS converted_orders, ROUND(COUNT(DISTINCT oi.order_id) * 100.0 / COUNT(DISTINCT o.order_id), 2) AS conversion_rate FROM orders o LEFT JOIN users u ON o.user_id = u.user_id LEFT JOIN order_items oi ON o.order_id = oi.order_id LEFT JOIN products p ON oi.product_id = p.product_id LEFT JOIN categories c ON p.category_id = c.category_id WHERE o.create_time >= DATE_SUB(NOW(), INTERVAL 30 DAY) AND o.order_status IN (1, 2, 3, 5) AND u.user_type = 'NORMAL' GROUP BY c.category_id, c.category_name ORDER BY conversion_rate DESC;

语法没问题,格式也工整。问题出在它"不知道"的东西上。

EXPLAIN输出告诉我真相

我在生产只读库上跑了EXPLAIN,结果让人头皮发麻:

| table | type | key | rows | Extra | |-------|------|-----|------|-------| | orders | range | idx_create_time | 860000 | Using where; Using temporary; Using filesort | | users | eq_ref | PRIMARY | 1 | Using where | | order_items | ALL | NULL | 1200000 | Using where; Using join buffer | | products | eq_ref | PRIMARY | 1 | NULL | | categories | eq_ref | PRIMARY | 1 | NULL |

order_items表走了全表扫描,rows估算120万行。生产库里order_items表有接近两千万行数据。这个查询在生产上跑完估计要超过40分钟。

问题出在哪里?AI不知道这张表的实际数据分布。它不可能知道——

order_items表缺少必要的索引。order_id字段虽然在order_items表里,但这个字段没有单独的索引,它只是联合主键(order_id, item_id)的一部分。MySQL优化器在某些情况下用不到联合主键的最左前缀。

隐式类型转换。oi.product_id = p.product_id看起来正常,但order_items.product_idvarchar(32)products.product_idbigint(20)。这种类型不一致在数据量小的时候无所谓,数据量大时索引直接失效。

N+1式统计。COUNT(DISTINCT oi.order_id)在大数据量下的去重计算代价极高。AI可以写出正确的SQL语法,但它不具备"这条SQL在生产库上跑会不会出问题"的判断力。

为什么AI不关心你的索引

这里有个根本性的问题要说清楚:AI生成SQL时看到的是"表结构"和"需求描述",它看不到——

生产中每张表的实际数据量和增长率。一张表有1万行和有2000万行,最优查询策略完全不同。

索引的实际选择性与碎片率。建了索引和索引真的被用到是两码事。order_items表上明明有联合主键,但实际执行计划里MySQL就是选了全表扫描。

MySQL优化器的版本差异。同样的SQL在MySQL 5.7和8.0上执行计划可能完全不同。AI默认参考的是通用文档,不会针对你的具体版本。

给AI加规则后重新生成

发现问题后我没有自己改SQL,而是重新问AI,这次加了规则:

"重写这条SQL,注意:order_items表有2000万行,product_id是varchar类型不是数值类型,避免DISTINCT在2000万行上的性能问题,先聚合再JOIN。"

这次AI生成的SQL好得多:

sql SELECT c.category_name, c.category_id, stats.total_orders, stats.converted_orders, ROUND(stats.converted_orders * 100.0 / stats.total_orders, 2) AS conversion_rate FROM ( SELECT p.category_id, COUNT(DISTINCT o.order_id) AS total_orders, COUNT(DISTINCT CASE WHEN oi.order_id IS NOT NULL THEN o.order_id END) AS converted_orders FROM orders o JOIN users u ON o.user_id = u.user_id AND u.user_type = 'NORMAL' LEFT JOIN order_items oi FORCE INDEX(idx_order_id) ON o.order_id = oi.order_id LEFT JOIN products p ON oi.product_id = p.product_id WHERE o.create_time >= DATE_SUB(NOW(), INTERVAL 30 DAY) AND o.order_status IN (1, 2, 3, 5) GROUP BY p.category_id ) stats JOIN categories c ON stats.category_id = c.category_id ORDER BY conversion_rate DESC;

改进点很实在:

用子查询先聚合再JOIN,减少了categories表参与中间结果集。

加了FORCE INDEX(idx_order_id)提示,因为我知道order_items表上有个单独的idx_order_id索引(AI不知道,但我说了它就会用)。

把类型不一致的问题明确告诉AI后,它不会再犯同样的错。

我现在怎么用AI写SQL

这件事之后,我写SQL的流程变成了这样:

先把需求按"表名 + 实际行数 + 索引列表 + 字段类型"的格式丢给AI。比如:

orders: 860万行, 索引idx_create_time(create_time), idx_user_status(user_id, order_status) order_items: 2000万行, 索引idx_order_id(order_id), 联合主键(order_id, item_id) product_id在order_items中是varchar(32),在products中是bigint(20) 需求:统计近30天各商品类目的订单转化率

然后等AI出SQL,我自己跑EXPLAIN看执行计划。如果type列出现ALL,就要追问AI:"这个表2000万行你让它全表扫?换个写法。"

几轮下来,AI产出的SQL质量明显提高。因为它从我的反馈里学到了"大表不能用ALL扫描"、"字段类型不同会导致索引失效"这些约束。

这不是AI变聪明了,是我给的上下文变丰富了。

我后来在团队里做了个分享,标题就叫"AI不知道你的表有多大"。分享完后一个同事说:"这不就是欺负AI没见过生产数据嘛。"我说对,所以你得替它见。

写SQL这件事上,AI能帮你省掉80%的敲键盘时间,但剩下的20%——理解数据规模、看懂执行计划、避开隐式类型转换——还得你自己来。这20%才是区分"能用"和"出事故"的关键。

http://www.jsqmd.com/news/993745/

相关文章:

  • 关于进程
  • VB.NET写的Modbus RTU串口调试小工具,支持线圈开关、寄存器读写和报文监控
  • 终极指南:使用ChromePass高效管理浏览器密码的完整方案
  • 2026杭州最新纺织厂/拉毛厂哪家工艺强,设备齐全,合作无套路 - 天天生活分享日志
  • 2026 汕尾黄金回收价位盘点 全城实体门店综合测评 - 靖昱黄金回收
  • PMBOK第七版视角:项目整合管理的核心实践与价值交付
  • GCC完全指南
  • 2026优选:双登蓄电池厂家,专业支撑铅酸工业电池与免维护电池的高效伙伴 - 企业推荐官【官方】
  • 实测干货! 2026上海落户机构推荐 TOP5 助力留学生职场人合规快速办理落户 - 资讯速览
  • 大模型之交互式应用(理论篇)
  • MiniMax M3 发布实测:国产模型编程能力首次超越 GPT-5.5
  • 多模态嵌入技术:模态间隙解析与优化策略
  • 企业级数据集成平台架构设计与技术实现深度解析
  • 从零构建一个AI驱动的英语单词默写小程序:技术架构全解析
  • 攻克Samba与Windows XP兼容难题:从协议降级到认证配置的实战解析
  • 2026佛山卡地亚手表回收避坑指南!佛山手表回收内行都懂的靠谱渠道 - 薛定谔的梨花猫
  • Visual Studio Code更新管理终极指南:如何轻松掌控版本更新
  • 昆明黄金回收避坑:报价高于大盘全是套路,教你一句话识破 - 奢侈品回收评测
  • 国内合规催化燃烧设备厂家实测排行权威盘点 - 起跑123
  • PostHog产品分析平台终极指南:从零到精通的开源数据分析解决方案
  • GR3-Fourier V9.4 底层硬核技术密档 纯裸源码+原始参数本文展示了工业控制领域的核心底层代码实现,包含四个关键部分:1) SVPWM空间矢量调制算法源码,详细给出扇区判定、时间计算和输出
  • 实战指南:基于ROS2与海康相机的rm_vision装甲板识别项目快速部署(视觉实战篇)
  • 从滤波到选频:RC/RL串联电路在Arduino和ESP32信号处理中的实战应用
  • 2026年Q2升降机厂家权威排名:TOP5推荐榜、国内知名升降机厂家、安徽升降机厂家推荐”、“安徽升降机厂家名单、升降机厂家电话18356581485 - 安互工业信息
  • 2026年众智商学院SCMP供应链管理专家报名:质量管理人员怎么学?模块选择、资料领取和课程咨询入口 - 众智商学院职业教育
  • 深圳PPH过滤器厂家排行:合规与场景适配实测对比 - 起跑123
  • 通俗易懂掌握树与二叉树:定义、核心概念与JS实现遍历
  • 郑州名包回收怎么选?多家门店行情对比参考 - 禹竞
  • CANN技术解读|metadef元数据结构与模型定义规范——深度解析昇腾CANN计算架构中基础数据层的核心设计
  • 计算机毕业设计之基于Python的教师科研成果数据管理系统的设计与实现