ORDER BY 默认按字段数据类型规则排序:数值比大小、日期比先后、字符串依字符集和排序规则(如 utf8mb4_general_ci 不区分大小写,utf8mb4_bin 按 ASCII 严格区分),多列排序从左到右逐级生效,NULL 值默认最小(升序在前),且不指定 ASC/DESC 时默认升序。

ORDER BY 默认就是按字母顺序排,但要注意字符集和大小写
直接写 ORDER BY column_name 确实能实现 A-Z 排序,但结果是否符合预期,取决于字段的字符集(如 utf8mb4)和排序规则(collation)。比如 utf8mb4_general_ci 是不区分大小写的,a 和 A 会被视为等价,排在一起;而 utf8mb4_bin 会按 ASCII 值严格排序,A(65)就排在 a(97)前面。
常见问题现象:Apple、apple、banana 混排,不是理想中的 “A, a, b” 或 “A, B, a”,而是全打乱或大小写穿插。
- 若想严格按 ASCII 顺序(即 A–Z 再 a–z),用
ORDER BY column_name COLLATE utf8mb4_bin - 若只想让大写优先且忽略重音符号(如 é ≈ e),选
utf8mb4_0900_as_cs(MySQL 8.0+) - PostgreSQL 不依赖 collation,而是靠
ORDER BY column_name默认按字节序,要大小写敏感可加COLLATE "C"
中文字段用 ORDER BY 也能按拼音首字母排?不能直接靠它
ORDER BY 对中文字段默认是按 Unicode 码点排序,不是拼音。例如 “北京”(U+5317)、“广州”(U+5E7F)、“上海”(U+4E0A)会按 5317 → 4E0A → 5E7F 排,结果是 “上海”、“北京”、“广州”,完全不是 A–Z 拼音首字母顺序。
真正可行的做法是借助数据库内置函数生成拼音首字母:
- MySQL 8.0+:需先用自定义函数或应用层转换,原生无拼音支持;常见做法是在写入时额外存一个
pinyin_first字段(如 “北”→“B”,“广”→“G”) - SQL Server:可用
COLLATE Chinese_PRC_CS_AS_KS_WS配合SUBSTRING+UNICODE做粗略映射,但不可靠 - 更稳的方式:在应用中用 Python 的
pypinyin或 Java 的pinyin4j提前算好首字母,写入数据库再ORDER BY pinyin_first
ORDER BY 多字段组合时,首字母排序容易被后续条件干扰
比如写成 ORDER BY LEFT(name, 1), created_at DESC,本意是“先按首字母分组,组内按时间倒序”。但如果 name 为空或 NULL,LEFT(name, 1) 返回 NULL,所有空值会挤在最前或最后(取决于数据库),破坏 A-Z 连续性。
实际使用中要注意:
- NULL 值默认排在最前(PostgreSQL)或最后(MySQL),可用
ORDER BY LEFT(name, 1) IS NULL, LEFT(name, 1), created_at DESC显式控制 - 首字母提取别用
SUBSTR(name, 1, 1)在 Oracle 中没问题,但在 SQLite 中要用SUBSTR(name, 1, 1),而 MySQL 中两者都行,但LEFT(name, 1)更直观 - 如果字段含空格或标点(如 “-Apple”),
LEFT(name, 1)会取到-,建议先TRIM再取:LEFT(TRIM(name), 1)
性能隐患:用函数包裹列会导致索引失效
写 ORDER BY UPPER(name) 或 ORDER BY LEFT(name, 1) 时,数据库无法直接走 name 字段的 B-tree 索引,只能全表扫描后排序,数据量一大就明显变慢。
优化思路很直接:
- 建函数索引(MySQL 8.0+、PostgreSQL、Oracle 支持):
CREATE INDEX idx_name_first ON table_name ((LEFT(name, 1))) - 更通用的做法:新增计算列并索引,如 MySQL 中
ALTER TABLE t ADD COLUMN name_first CHAR(1) GENERATED ALWAYS AS (LEFT(TRIM(name), 1)) STORED,再对name_first建索引 - 避免在 ORDER BY 里做 NLS 转换(如
NLS_SORT = 'BINARY_AI'),这在 Oracle 中也绕不开函数开销
首字母排序看着简单,真正上线前得确认字符集、处理 NULL、防函数索引失效——这三个点漏掉任一个,查出来顺序对不上,或者某天查 10 万行突然卡住,都是大概率事件。










