sql关键字查询
昨天帮同事排查一个慢查询,键字他写了一条 SELECT * FROM orders WHERE status = 'pending',查询跑了三秒多。键字表里才二十万行,查询这速度不对劲。键字我让他把执行计划拉出来一看,查询全表扫描。键字问题出在哪?查询status 字段没建索引,但更隐蔽的键字是,他压根没想过 EXPLAIN 这个关键字能救他。查询
SQL 关键字这东西,键字平时写 SELECT、查询WHERE、键字JOIN 跟呼吸一样自然,查询可一到性能瓶颈或者逻辑混乱时,键字真正管用的往往是那些被忽略的冷门货。拿 EXISTS 来说,它跟 IN 的差别,很多人只在面试题里背过,实际写代码时随手就用 IN。但子查询返回的结果集一大,IN 会把整个结果集加载到内存里比对,EXISTS 则是逐行判断存在性,走索引时快得不是一点半点。
我见过最离谱的一次,是有人用 NOT IN 查空值。表里 deleted_at 允许为 NULL,他写 WHERE id NOT IN (SELECT order_id FROM refunds WHERE deleted_at IS NULL),结果返回空集。为什么?因为 NOT IN 遇到 NULL 会直接短路——子查询里只要有一条 order_id 是 NULL,整个条件就变成“未知”,一行都查不出来。换成 NOT EXISTS 就没事。这种坑,文档里写得明明白白,但你不撞一次墙根本记不住。
关键字查询还有个容易翻车的地方,就是 LIKE 的模糊匹配。很多人写 LIKE '%关键词%',前置通配符直接把索引废掉。可业务上确实需要“包含”搜索,怎么办?MySQL 里可以用 LOCATE 或 INSTR,但性能一样差。真正该做的是上全文索引或者 Elasticsearch,而不是纠结关键字本身。但如果你只是临时查一次数据,LIKE 加个右通配符 '关键词%' 就能走索引,差别立竿见影。
还有 GROUP BY 和 HAVING 的配合。新手常犯的错是拿 WHERE 去过滤聚合结果,比如“查订单数超过 10 的用户”,写成 WHERE COUNT(*) > 10,直接报错。正确写法是 GROUP BY user_id HAVING COUNT(*) > 10。但 HAVING 别滥用,它是在分组后过滤,如果能在 WHERE 阶段先缩小数据范围,就别偷懒。
说回开头的慢查询。我让他改成 SELECT * FROM orders WHERE status = 'pending' AND created_at > NOW() - INTERVAL 7 DAY,然后给 (status, created_at) 建了联合索引,查询时间降到 80 毫秒。他没改任何业务逻辑,只是多用了两个关键字和一层索引。
SQL 关键字就像工具箱里的螺丝刀,一字、十字、内六角各有用途。你天天用 SELECT 不代表会查数据,能把 EXPLAIN、EXISTS、HAVING 这些“备胎”用对地方,才算真正入门。下次写查询前,先问自己一句:这个关键字是不是最优解?大概率能少踩几个坑。