当前位置:首页 > 休闲 > sql检查 正文

sql检查

来源:烟消火灭网   作者:百科   时间:2026-10-17 05:51:06

上周排查一个线上问题,订单表里出现了两条完全相同的记录,除了自增主键不同,其余字段一模一样。开发第一反应是“并发插入没加锁”,折腾半天改代码。我看了眼他的 SQL,发现问题根本不在这儿——他的查询条件里用了 WHERE status != 2,而 status 字段允许为 NULL。NULL 跟任何值比较都返回未知,那些 status 为空的记录被他以为过滤掉了,实际上一条都没滤掉,业务逻辑判断自然出错。

这种事见得太多了。SQL 写出来能跑,不代表写对了。数据库不会报错,它只是安静地给你一个错误的结果。

先看执行计划,别猜

很多人调优 SQL 的习惯是凭感觉加索引。哪个字段在 WHERE 里出现频率高就加哪个,复合索引的字段顺序全凭直觉排列。我见过一张三百万行的表上建了十几个单列索引,查询还是慢。让他跑一下 EXPLAIN,发现 MySQL 压根没走他建的那些索引,因为优化器算了一下,全表扫描反而更快。

执行计划里几个关键信息值得盯:type 列如果是 ALL,说明全表扫描;rows 列估算的扫描行数跟你预期差多少;Extra 里出现 Using filesort 或 Using temporary,基本可以判断排序或分组没走索引。这些比任何经验判断都直接。

NULL 是绕不过去的坑

回到开头那个案例。NULL 在 SQL 里不是“空字符串”,不是“0”,它是一个逻辑上的“未知”。NULL = NULL 的结果不是 TRUE,是 NULL。所以 WHERE column = NULL 永远查不出任何行,必须用 IS NULL。

更隐蔽的是聚合函数。COUNT(*) 统计所有行,COUNT(column) 跳过 NULL 值。同一条 SQL 里两个 COUNT 出来的数字不一样,如果没意识到这一点,报表数据就能对不上。还有 NOT IN 子查询,如果子查询结果集里包含 NULL,整个 NOT IN 返回空结果集。这个行为反直觉,但确实是标准 SQL 的定义。

索引不是越多越好

我自己的经验是,一张表的索引数量控制在五个以内。每个索引都要维护 B+ 树结构,写入时逐个更新,插入性能下降是实打实的。更麻烦的是复合索引的字段顺序——把区分度低的字段放前面,比如性别、状态这种只有几个值的列,索引基本废掉。

联合索引有个“最左前缀”原则。建了 (a, b, c) 的索引,查询条件只带 b 和 c 用不上,只带 a 和 c 只能用到 a 的部分。范围查询之后的字段也会失效,比如 WHERE a = 1 AND b > 2 AND c = 3,c 用不到索引。这些规则写起来简单,实际写 SQL 时经常忘。

别在数据库里做应用层的事

见过用存储过程实现完整业务逻辑的系统,几千行 SQL 嵌套游标循环。出了问题没法调试,改一行要测半天,版本管理也麻烦。数据库擅长的是数据存取和集合运算,不是流程控制。把复杂逻辑拆到应用层,SQL 保持简单直接,维护成本低得多。

还有个常见毛病是在 WHERE 里对字段做函数运算,比如 WHERE DATE(create_time) = '2024-01-01'。这会让索引失效,因为数据库没法用索引去匹配函数计算后的值。改成 WHERE create_time >= '2024-01-01' AND create_time < '2024-01-02',索引用得上,结果一样。

SQL 检查这件事,工具能帮一部分忙,比如语法校验、简单的性能分析。但逻辑层面的问题——NULL 处理、索引设计、查询语义——还是得靠人对数据和业务的理解。写完 SQL 别急着提交,拿几条边界数据跑一下,看看结果是不是你真正想要的。这个习惯能省掉很多事后排查的时间。

标签:

责任编辑:综合