SELECT 是什么
SELECT 是 SQL 的读取入口,把满足条件的行按指定的列投影出来。它的书写顺序是 SELECT、FROM、WHERE、GROUP BY、ORDER BY、LIMIT,而真实执行顺序是 FROM、WHERE、GROUP BY、HAVING、SELECT、ORDER BY、LIMIT。理解这个差异就明白为什么别名能在 ORDER BY 里用、在 WHERE 里却用不了。生产环境里列投影越窄越好:只取需要的列,覆盖索引才有机会生效,网络与客户端内存开销同步下降。
基本信息
| 用途 | 读取数据与列投影 |
|---|---|
| 语法 | SELECT 列表 [FROM 表] [WHERE 条件] [GROUP BY 列] [HAVING 条件] [ORDER BY 列] [LIMIT n] |
| 执行顺序 | FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT |
| 别名规则 | ORDER BY 可引用别名,WHERE 不能 |
| 权限要求 | 账号具备目标表的 SELECT 权限 |
| 版本差异 | MySQL 5.7 无 CTE,8.0 支持 CTE 与窗口函数 |
典型使用场景
- 核对业务数据:只列需要的列,避免一次拉回整行宽表
- 生成报表或导出:用表达式与别名把计算直接算好,减少后续处理
- 巡检脚本取指标(行数、状态分布),配 -B 输出送监控采集
- 分页列表接口的基础查询,配合排序与 LIMIT 使用
- 排查数据异常时先 SELECT 确认影响范围,再决定写操作的条件
- 用 LIMIT 抽样了解表结构与数据形态,避免全表扫描拖垮实例
常用示例
常用示例
SELECT id, sku, qty, price FROM orders; # 明确列投影,替代 SELECT *
SELECT id AS order_id, qty * price AS amount FROM orders; # 表达式计算并起别名
SELECT CONCAT('ORD-', id) AS order_no, created_at FROM orders # 字符串拼接,加范围过滤
WHERE created_at >= '2026-10-01' AND created_at < '2026-10-02';
SELECT DISTINCT status FROM orders; # 取去重枚举值,快速看清状态集合
SELECT COUNT(*) AS total FROM orders WHERE status='paid'; # 计数单独跑,别和明细混在一起
SELECT id, amount FROM orders WHERE user_id = 1001 LIMIT 10; # 查明细务必带 LIMIT执行顺序逐阶段读法
| 阶段 | 做什么 | 常见疑问 |
|---|---|---|
| FROM | 确定数据来源,完成多表连接 | 多表 JOIN 在这里完成,不是最后 |
| WHERE | 行级过滤,作用在原始行上 | 此处不能引用 SELECT 里的别名 |
| GROUP BY | 按列分组,行数开始收敛 | 分组列的选择直接决定结果粒度 |
| HAVING | 对分组结果过滤 | 可引用聚合函数,WHERE 不行 |
| SELECT | 计算列与生成别名 | 别名在这一步才真正产生 |
| ORDER BY | 排序,可使用别名与列序号 | 排序字段不唯一会导致分页错乱 |
| LIMIT | 截断返回行数 | 在排序之后生效,影响的是返回集 |
反例与改写
反例与改写
# 反例:函数包住索引列,索引无法使用
SELECT id, created_at FROM orders WHERE DATE(created_at) = '2026-10-12';
# 改写:改范围条件,索引恢复可用
SELECT id, created_at FROM orders
WHERE created_at >= '2026-10-12' AND created_at < '2026-10-13';
# 反例:只需要两列却拉回整行
SELECT * FROM orders WHERE user_id = 1001;
# 改写:只取需要的列,才有机会走覆盖索引
SELECT id, amount FROM orders WHERE user_id = 1001;SELECT * 在宽表或含大字段(TEXT、BLOB)的表上会把不需要的数据全部读出来,覆盖索引失效,网络传输与客户端内存开销同时上升;只有在查看表结构或临时排查时才适合用。
只读查询一样可以造成影响:大表全表扫描会占满 buffer pool 与磁盘 IO,线上临时查询请自带 LIMIT、避开业务高峰,耗资源的统计尽量在只读从库执行。
MySQL 8.0 起支持 CTE 与窗口函数,复杂统计可以先用 WITH 定义中间结果集再关联;5.7 不具备这些能力,写需要跨版本复用的 SQL 时要先确认目标版本。
列投影与索引的配合
- 查询涉及的列全部落在同一个索引上时可只读索引不回表,宽表场景收益最明显
- 把不需要的大字段从投影里去掉,往往就直接消除了回表开销
- 投影列与过滤条件尽量落在同一复合索引上,减少回表与临时排序
- 统计类查询先确认是否需要精确值,估算场景可用统计信息替代全量计数
- 列顺序与索引定义不一致时,最左前缀用不上的列会退化为扫描
列别名只在当前语句内有效、不能跨语句复用:需要长期统一的取数口径应落到视图或应用层,否则每个报表各写一遍,同一个指标会算出不同结果。