应显式指定SELECT列名而非使用*,避免性能下降、敏感数据泄露及ORM映射异常;WHERE/GROUP BY/ORDER BY中不可直接引用AS别名;函数操作字段需注意索引失效与隐式转换;UNION各子句须列数、类型、顺序一致。

SELECT 语句里只写要的列,别用 *
查指定列本质就是显式列出字段名,而不是依赖 *。用 * 不仅拖慢查询(尤其表有大字段或很多列时),还容易在后续加字段后意外带出不该暴露的数据,比如 password_hash 或 deleted_at。
常见错误现象:SELECT * FROM users 在开发阶段看着方便,上线后发现接口响应变慢、API 返回了敏感字段、ORM 映射报错(比如 JSON 序列化遇到 blob 字段)。
- 明确写出需要的列,例如:
SELECT id, name, email FROM users - 如果列名含特殊字符或关键字,用反引号包裹:
SELECT `order`, `group` FROM sales - 避免在应用层依赖列顺序 —— 别写
SELECT id, name FROM users然后用row[0]取 ID,应改用字段名访问
用 AS 给字段起别名时注意作用域
AS 是给投影结果重命名,只影响最终结果集的列名,不影响 WHERE、GROUP BY 或 ORDER BY 中的引用(除非用子查询或 CTE)。很多人误以为写了 SELECT name AS username FROM users WHERE username = 'alice' 能生效,其实会报错:Unknown column 'username' in 'where clause'。
使用场景:前端展示字段需统一命名、聚合计算后标识含义、联表时避免列名冲突。
- WHERE / GROUP BY / ORDER BY 中仍须用原始列名或表达式,例如:
SELECT name AS username FROM users WHERE name = 'alice' - 若真想在后续子句用别名,得包一层子查询:
SELECT * FROM (SELECT name AS username FROM users) t WHERE t.username = 'alice' - 别名不支持嵌套表达式缩写,比如不能写
SELECT CONCAT(first_name, ' ', last_name) AS full_name ORDER BY full_name—— MySQL 5.7+ 允许,但 5.6 及更早版本不支持,建议显式重复表达式或改用子查询
NULL 值和函数投影要小心隐式类型转换
对字段做函数操作(如 UPPER()、DATE()、COALESCE())属于“表达式投影”,MySQL 会为结果生成临时列,但可能触发隐式转换,导致索引失效或比较逻辑异常。
性能影响明显:比如 SELECT UPPER(email) FROM users WHERE UPPER(email) = 'TEST@EXAMPLE.COM',即使 email 有索引,也用不上。
- 尽量把函数移到等号右边,让左边保持字段原样:
WHERE email = LOWER('TEST@EXAMPLE.COM') -
COALESCE(name, 'anonymous')投影没问题,但如果name是TEXT,而默认值是字符串,MySQL 可能按最大长度分配内存,影响排序/分组性能 - 涉及时间字段时,
DATE(created_at)会丢掉索引;如需按天查询,考虑建生成列索引:ALTER TABLE users ADD COLUMN created_date DATE AS (DATE(created_at)) STORED,再对created_date建索引
联合查询中字段投影必须一一对应
用 UNION 合并多个 SELECT 时,各子句的列数、类型、顺序必须一致,否则报错:The used SELECT statements have a different number of columns 或隐式转成字符串导致数值截断。
容易踩的坑是忽略 NULL 占位或类型对齐 —— 比如第一个 SELECT id, name,第二个写成 SELECT id, COUNT(*),虽然都是两列,但 name(字符串)和 COUNT(*)(整数)在 UNION 时会被强制转成同一类型,可能出人意料的结果。
- 显式补全缺失字段,用
NULL或类型兼容的默认值:SELECT id, name, NULL AS total FROM users UNION SELECT user_id, NULL, amount FROM orders - 必要时用
CAST()统一类型:SELECT id, CAST(name AS CHAR) FROM users UNION SELECT id, CAST(age AS CHAR) FROM profiles -
UNION ALL比UNION快(不排重),如果业务确定无重复,优先选UNION ALL
字段投影看着简单,但实际牵扯到执行计划、索引利用、数据一致性,甚至 ORM 的映射行为。最常被忽略的是:你以为只是“少查几个字段”,但数据库可能因此放弃使用覆盖索引,或者应用层拿到空字符串而非 NULL,然后崩在 JSON 序列化那一步。










