如何最优实现基于关联表日期最值范围过滤requests表数据?
我拥有两张表,分别为requests和dates(为简化表述进行了转述):
CREATE TABLE requests (id serial4 NOT NULL); --以及相关约束 CREATE TABLE dates (id serial4 NOT NULL, request_id serial4 NOT NULL, date_col date NOT NULL); --相关约束,request_id 关联 requests.id
我希望依据beginDate和endDate两个参数对返回的requests数据进行过滤。
我当前的实现方式如下:
SELECT id FROM requests WHERE (SELECT MAX(date_col) as max_date FROM dates WHERE dates.request_id = requests.id) <= ? AND (SELECT MIN(date_col) as min_date FROM dates WHERE dates.request_id = requests.id) >= ?
但我认为一定存在更优的实现方式。我曾考虑使用INNER JOIN,但由于仅用dates表做过滤,无需查询其字段,且会导致requests数据出现不必要的重复,因此认为该方案并不合适。
我尝试在WHERE子句的同一个子查询中同时查询MIN()和MAX(),但只能引用其中一个查询结果(例如(SELECT ...).min_date),且该场景下不允许使用AS关键字。
我也考虑过创建包含min_date和max_date的VIEW,但仅在此处使用的话显得过于冗余。
我是否忽略了某些显而易见的方案?在当前需求下,我现有的繁琐实现是否已是最优选择?
有两种更高效简洁的实现方式,可根据实际场景选择:
方式一:使用EXISTS结合聚合子查询
通过EXISTS判断关联的dates记录是否满足日期范围条件,仅需一次子查询即可完成min和max的聚合判断,不会产生重复数据:
SELECT id FROM requests r WHERE EXISTS ( SELECT 1 FROM dates d WHERE d.request_id = r.id HAVING MIN(d.date_col) >= ? AND MAX(d.date_col) <= ? )
这种方式避免了原方案中两次独立子查询的重复开销,性能更优。
方式二:预聚合dates表后关联
先对dates表按request_id聚合出最小和最大日期,再与requests表关联过滤,每个request_id仅对应一条聚合结果,不会产生重复:
SELECT r.id FROM requests r JOIN ( SELECT request_id, MIN(date_col) AS min_date, MAX(date_col) AS max_date FROM dates GROUP BY request_id ) d ON r.id = d.request_id WHERE d.min_date >= ? AND d.max_date <= ?
当dates表数据量较大时,预聚合能大幅减少关联的数据量,提升查询效率。
原方案的问题
原方案中每条requests记录都会触发两次独立的子查询(分别计算max和min日期),当requests表数据量较大时,会产生大量重复查询,性能开销较高。上述两种方案均将两次查询合并为一次,能显著优化执行效率。
内容的提问来源于stack exchange,提问作者András Ballai

