视图中distinct仅对整行去重,若select含主键或时间戳等高区分度字段,则无法消除业务逻辑上的重复;应按需选用group by、窗口函数或精简字段列表。

DISTINCT 在视图里和普通查询里行为完全一致,它不是“过滤重复记录”的开关,而是对整行结果做去重——只要 SELECT 列表中所有字段值完全相同,才视为重复。
为什么视图里写 DISTINCT 却没去重?
常见错误是把视图当成“按某列去重”的工具。比如定义视图:
CREATE VIEW unique_companies AS SELECT DISTINCT company, id, created_at FROM orders;
结果发现公司名还是重复——因为 id 和 created_at 几乎必然不同,整行永远不会重复。
- 视图只是封装了 SELECT 逻辑,
DISTINCT仍按标准规则作用于整个输出行 - 如果业务上认为“公司名相同就算重复”,那 SELECT 列表里就不能出现
id、created_at这类高区分度字段 - 视图定义中混入主键或时间戳字段,等于主动禁用
DISTINCT效果
DISTINCT 和 GROUP BY 在视图里能互换吗?
语法上,SELECT DISTINCT a, b FROM t 和 SELECT a, b FROM t GROUP BY a, b 在多数数据库返回相同结果,但在视图定义中差异明显:
-
DISTINCT视图不能后续加聚合(如SELECT *, COUNT(*)),会报错 -
GROUP BY视图天然支持扩展:你可以在外层再套一层查询,加HAVING或其他聚合 - MySQL 5.7+ 严格模式下,
GROUP BY视图若漏写非分组字段,定义阶段就失败;DISTINCT视图则更宽松,但容易掩盖语义问题
视图里用 DISTINCT 的性能隐患
视图本身不执行,但每次查询视图时,DISTINCT 都会触发实际去重操作。问题集中在:
- 没有索引支撑的字段组合(如
SELECT DISTINCT UPPER(name), city)无法走索引,强制全表扫描 + 排序 - 视图被嵌套在多层查询中时(例如
SELECT * FROM unique_companies WHERE city = 'Beijing'),优化器可能无法下推谓词,导致先去重再过滤,白白消耗资源 - PostgreSQL 支持
DISTINCT ON (column),但这是非标语法,用在视图里会降低可移植性
真正需要“按某列保留一条”的场景怎么办?
DISTINCT 在视图里做不到“每组取最新/最小 ID 的那条”。比如要每个 company 只留 created_at 最大的那条记录:
- 别硬套
DISTINCT,视图里直接用窗口函数更可靠:CREATE VIEW latest_company_orders AS SELECT company, id, created_at FROM ( SELECT company, id, created_at, ROW_NUMBER() OVER (PARTITION BY company ORDER BY created_at DESC) AS rn FROM orders ) t WHERE rn = 1; - 如果目标数据库不支持窗口函数(如旧版 MySQL),视图里用相关子查询风险极高——执行效率差,且可能因 NULL 或空集出错
- 简单去重需求明确、字段少、数据量可控时,
DISTINCT视图才合适;一旦涉及“取代表行”,就得跳出DISTINCT思维
复杂点在于:视图定义时看不出性能问题,只有在高并发或大数据量查询时才暴露。最容易被忽略的是字段选择——多一个看似无害的 updated_at,就可能让 DISTINCT 彻底失效。











