sql注意事项
作者:探索 来源:休闲 浏览: 【大 中 小】 发布时间:2026-10-17 06:13:28 评论数:
SQL这东西,意事用得好是意事利器,用不好就是意事给自己挖坑。我见过太多线上事故,意事十有八九跟下面这几个细节有关。意事 先说NULL。意事很多人写WHERE条件时想当然,意事比如查“没填写手机号的意事用户”,顺手就是意事`WHERE phone != ''`。结果呢?意事phone是NULL的行全被过滤掉了。NULL不等于空字符串,意事NULL跟任何值比较都返回UNKNOWN,意事包括`NULL = NULL`。意事所以判断NULL只能用`IS NULL`或`IS NOT NULL`。意事这个坑,意事新手踩,老手也踩,区别只是老手踩完能快速反应过来。 再说索引失效。你建了索引,但查询没走,等于白建。最常见的情况是对索引列做了函数运算或隐式类型转换。比如`WHERE DATE(create_time) = '2024-01-01'`,这会让create_time上的索引失效,全表扫描。正确写法是`WHERE create_time >= '2024-01-01' AND create_time < '2024-01-02'`。还有,如果字段是varchar类型,你传了数字进去,MySQL会隐式转换,索引照样失效。这种问题排查起来特别隐蔽,因为单条数据量小的时候根本感觉不到慢,等数据量上去了,查询直接卡死。 分页查询也有讲究。`LIMIT 100000, 20`这种写法,越到后面越慢。因为数据库得先扫描前十万行,然后再丢弃。我见过一个后台管理页面,翻到第几百页时响应时间飙到十几秒。解决办法是用子查询先定位主键:`WHERE id > (SELECT id FROM table ORDER BY id LIMIT 100000, 1) LIMIT 20`。或者干脆记住上一页最后一条的id,用`WHERE id > 上一页最大id`来翻页,性能提升立竿见影。 事务隔离级别这事儿,很多人压根没概念。默认的REPEATABLE READ在MySQL里,如果两个事务同时更新同一行,后提交的那个会直接报死锁错误,而不是等待。我遇到过开发人员抱怨“明明代码没问题,就是偶尔报错”,最后查出来是两个接口并发调用了同一行数据的更新。解决思路要么调整业务逻辑减少锁竞争,要么显式使用`SELECT ... FOR UPDATE`来管理锁顺序。别指望数据库自动帮你处理好一切。 还有一个容易被忽略的点:字符集和排序规则。表用了utf8mb4_general_ci,另一张表用utf8mb4_unicode_ci,两张表JOIN的时候,如果关联字段是varchar,可能会因为排序规则不一致导致索引失效,甚至直接报错。更麻烦的是,有些老表是utf8,不是utf8mb4,存不了emoji,插入特殊字符直接报错。建表之前想清楚字符集,上线之后再改,代价是重建全表。 最后说个实际案例。之前有个报表查询,跑了三分钟,业务方天天催。我一看SQL,里面有个`LEFT JOIN`,但关联条件里写了`ON a.id = b.user_id AND b.status = 1`。这个写法本身没错,问题在于b表的数据量是几千万,而status字段的区分度太低,只有0和1两个值,索引基本没用。优化方式是把status的过滤条件放到WHERE里,或者干脆拆成两步查询,先取出符合条件的b表id,再关联。改完之后,查询时间降到了两秒以内。 SQL写得好不好,直接决定了系统的上限。别光顾着写业务代码,多花点时间看执行计划,用`EXPLAIN`分析一下,很多坑都能提前避开。数据量小的时候,什么写法都能跑,等数据量大了,欠的债迟早要还。
