应明确指定所需列名而非使用SELECT *,以提升性能、保障安全、增强可维护性;需避免大字段读取、列名冲突、索引失效及NULL/类型隐式转换风险,并通过EXPLAIN验证执行计划。

SELECT 后面只写需要的列名,别用 *
* 看起来省事,但实际会拖慢查询、增加网络传输、暴露不该暴露的字段。比如表有 user 表共 20 列,你只需要 id、name、email,那就明确写出来:
SELECT id, name, email FROM user;
- 如果某列是
TEXT或JSON类型(比如profile),而你根本不用它,*会让数据库多读几百 KB 数据 - 某些 ORM(如 Django 的
values())或中间件会隐式加*,得检查生成的 SQL - 别在
SELECT里写user.*除非真要全部字段——尤其做JOIN时,容易引发列名冲突
用别名简化长字段名或表达式结果
字段名太长(比如 created_at_timestamp_utc)或带函数(比如 UPPER(name)),不加别名会导致结果集列名难读、应用层取值出错:
SELECT id, UPPER(name) AS name_upper, DATE(created_at) AS date_only FROM user;
- 应用代码里必须用
name_upper取值,不是UPPER(name) - 别名不能用引号包裹(除非含空格或关键字),否则不同数据库行为不一致:
AS "full name"在 PostgreSQL 可行,MySQL 默认会报错 - 如果别名和原表字段重名(比如
SELECT name AS name),多数数据库允许,但可读性差,建议避免
WHERE 条件里别误推「只查几列」能跳过索引扫描
有人以为“我只选 3 列,数据库应该很快”,但实际执行计划仍可能走全表扫描——关键看 WHERE 条件是否命中索引:
SELECT id, status FROM order WHERE user_id = 123;
- 即使只查两列,如果
user_id没建索引,还是得扫全表 - 更糟的是:如果
SELECT的列不在联合索引覆盖范围内,数据库可能回表(比如 InnoDB 的二级索引查不到status,还得去聚簇索引捞),这时加个INCLUDE(SQL Server)或建覆盖索引(MySQL 8.0+)才真正提速 - 用
EXPLAIN看Extra字段:出现Using index才算纯索引扫描;Using where; Using index是理想状态
注意 NULL 和类型隐式转换对结果的影响
选出来的列如果参与后续逻辑(比如前端直接渲染、或拼进另一个查询),NULL 值和类型不一致会悄悄出问题:
SELECT id, phone, COALESCE(phone, 'N/A') AS phone_display FROM user;
-
phone是VARCHAR,但某些导出工具或 JDBC 驱动可能把NULL当成空字符串,导致前端显示空白而非“暂无” - 如果
id是BIGINT,但 JavaScript 前端直接JSON.stringify(),可能丢失精度(超过2^53的整数),这时要么后端转成字符串,要么 SELECT 时显式CAST(id AS CHAR) - 别依赖数据库默认的列类型别名——比如
SELECT 1 + 1返回列名可能是1 + 1(MySQL)或?column?(PostgreSQL),必须用AS
字段越少,责任越具体。漏掉一个 COALESCE,前端就可能崩;少看一眼 EXPLAIN,线上就可能慢三秒。

















