为什么同一条SQL查询作为子查询使用时返回结果不一致?
问题根本原因
你遇到的问题是绝大多数关系型数据库(尤其是旧版本MySQL、PostgreSQL)都存在的关联子查询优化bug:当关联子查询中同时使用ORDER BY 非唯一字段 DESC + LIMIT 1的结构时,优化器会错误判定ORDER BY子句无意义,直接返回第一条满足WHERE条件的记录,而非排序后的第一条记录。
单条查询时没有外层关联逻辑,优化器不会触发这个bug,所以返回结果正确;在关联子查询场景下触发了优化bug,就返回了乱序的结果14321。
验证方法
你可以通过以下操作确认是该问题:
给子查询的ORDER BY后追加唯一列排序,修改子查询为:
SELECT config_timeslice_id FROM config_timeslice WHERE config_id = t.config_id AND created <= CURRENT_TIMESTAMP ORDER BY created DESC, config_timeslice_id DESC LIMIT 1
如果修改后返回结果为预期的14325,即可确认是优化器丢弃排序规则导致的问题。
如果修改排序规则后仍然返回错误结果,请检查created字段的数据类型:如果该字段是字符串类型存储时间值,会出现不符合预期的排序结果,需要先使用时间转换函数(如MySQL的STR_TO_DATE)将字段转为时间类型后再排序。
更稳定的替代写法
建议避免在关联子查询中使用排序+limit的结构,改用以下两种更稳定的写法实现相同逻辑:
方案1:窗口函数法
WITH ranked_slice AS ( SELECT config_id, config_timeslice_id, ROW_NUMBER() OVER (PARTITION BY config_id ORDER BY created DESC) AS rn FROM config_timeslice WHERE created <= CURRENT_TIMESTAMP ) SELECT DISTINCT config_id, config_timeslice_id AS ts_id FROM ranked_slice WHERE rn = 1
方案2:先聚合最大时间再关联
SELECT a.config_id, b.config_timeslice_id AS ts_id FROM ( SELECT config_id, MAX(created) AS max_created FROM config_timeslice WHERE created <= CURRENT_TIMESTAMP GROUP BY config_id ) a LEFT JOIN config_timeslice b ON a.config_id = b.config_id AND a.max_created = b.created
内容的提问来源于stack exchange,提问作者John Lindal
相关产品推荐
相关产品推荐

