-- 假设索引: idx(a, b, c)-- ① 最左前缀缺失SELECT * FROM t WHERE b = 1; -- ❌ 没有 a,不走索引-- ② 中间断档SELECT * FROM t WHERE a = 1 AND c = 2; -- ⚠️ 只用 a,b 缺失后 c 失效-- ③ 范围查询后的列失效SELECT * FROM t WHERE a = 1 AND b > 5 AND c = 2;-- ✅ a 精确 + b 范围 → 只用 a+b,c 不走索引-- ④ 函数/运算SELECT * FROM t WHERE YEAR(create_time) = 2025; -- ❌SELECT * FROM t WHERE create_time >= '2025-01-01'; -- ✅-- ⑤ 隐式类型转换SELECT * FROM t WHERE phone = 13800138000; -- ❌ phone 是 VARCHAR-- ⑥ LIKE 前导模糊SELECT * FROM t WHERE name LIKE '%kiyose'; -- ❌SELECT * FROM t WHERE name LIKE 'kiyose%'; -- ✅
EXPLAIN 速读
EXPLAIN SELECT * FROM orders WHERE user_id = 5;-- type: const > eq_ref > ref > range > index > ALL-- 好 ←─────────────────────→ 差-- key: NULL = 没走索引-- rows: 扫描行数,越小越好-- Extra: Using filesort = 需要额外排序(加索引)-- Using temporary = 需要临时表(改 SQL 结构)
错误: SQLITE_BUSY: database is locked原因: SQLite 同时只允许一个写者解决: ① PRAGMA journal_mode=WAL -- 读写可并发 ② PRAGMA busy_timeout=5000 -- 等 5 秒不立即报错 ③ 批量写入放在同一事务中
坑 2:MySQL 隐式锁升级
-- ❌ 大范围 UPDATE 导致锁表UPDATE orders SET status = 'expired' WHERE create_time < '2024-01-01';-- 可能锁住百万行 → 其他事务阻塞 → 连接池打满-- ✅ 分批更新UPDATE orders SET status = 'expired'WHERE create_time < '2024-01-01' LIMIT 1000;-- 循环执行直到 affected_rows = 0
坑 3:自增 ID 耗尽
-- INT 自增上限 ≈ 21 亿,高频插入 2-3 年用完-- ✅ 用 BIGINTCREATE TABLE events ( id BIGINT AUTO_INCREMENT PRIMARY KEY, ...);
坑 4:NULL 的比较陷阱
-- NULL 不是值,不能用 =SELECT * FROM t WHERE col = NULL; -- ❌ 永远返回空SELECT * FROM t WHERE col IS NULL; -- ✅-- NULL 在唯一索引中CREATE UNIQUE INDEX idx ON t(col); -- 允许多个 NULL!-- 因为 NULL != NULL,唯一约束对 NULL 失效