SELECT * 真的能查出“全部字段”吗?
不能。
SELECT *只返回当前
FROM子句指定表(或视图、子查询)中**定义的可见字段**,不包括:计算列(除非显式定义为生成列)、注释字段、被
REVOKE权限隐藏的列、临时表中已失效的列,以及 JOIN 后未去重的同名列(会报错或被自动别名化)。实际执行时,MySQL 会先解析表结构,再展开为具体字段列表——所以它查的是“元数据里此刻存在的字段”,不是“你印象中的全部”。
想安全获取某张表所有字段名,用 INFORMATION_SCHEMA
依赖
SELECT *写法做自动化或建模是危险的,字段增减会导致结果错位或程序崩溃。更可靠的方式是查系统表:
SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'your_db_name' AND TABLE_NAME = 'your_table_name' ORDER BY ORDINAL_POSITION;
注意:
TABLE_SCHEMA必须写对,尤其在多库共用连接时;
ORDINAL_POSITION是真实定义顺序,比按
COLUMN_NAME排序更准确。
SELECT * 在 JOIN 场景下容易触发错误或歧义
当多个表有同名字段(比如都含
id、
created_at),直接
SELECT *会导致结果集字段名冲突,PHP/Python 的 fetch 操作可能只取到其中一个值,甚至 MySQL 8.0+ 会直接报
ERROR 1052 (23000): Column 'xxx' in field list is ambiguous。 必须显式列出字段,并用表别名限定:
SELECT u.id, u.name, o.status FROM users AS u JOIN orders AS o ON u.id = o.user_id如果真需要全部字段且确定无冲突,可用
tbl.*限定范围:
SELECT u.*, o.order_no, o.amount避免
SELECT * FROM a JOIN b这种裸写法——即使当前没同名字段,后续加字段就埋雷
性能和可维护性上,* 比显式列名慢且难调试
MySQL 优化器对
SELECT *的处理并不“智能”:它仍需读取所有字段对应的数据页,即使你只用其中 2 列;网络传输、序列化、内存分配开销都更高。更重要的是,日志、监控、慢查分析里看到的都是
*,无法快速定位是哪个字段拖慢了查询。 线上环境禁止在大表(行数 > 10 万 或 单行宽度 > 2KB)上用
SELECT *ORM 中配置
select: ['id', 'title']明确优于
select: '*'开发阶段用
SELECT *快速验证可以,但提交前必须换成明确字段列表
字段顺序、是否允许 NULL、默认值这些细节,只有显式写出字段才能让 SQL 自带文档性。靠
*隐藏复杂度,最后只会让问题更难定位。
