针对特定案例的 SQL 性能改进

问题描述 投票:0回答:1

我有两张桌子,如下所示:

A

爱德, 出价 日期1 日期2
1 B1 2021 年 1 月 1 日 2021 年 12 月 31 日
1 B1 2022 年 1 月 1 日 2022 年 12 月 31 日
1 B1 2023 年 1 月 1 日 2030 年 12 月 31 日
2 B2 2021 年 1 月 1 日 2030 年 12 月 31 日
3 B3 2024 年 1 月 1 日 2030 年 12 月 31 日

B

出价 B值
B1 B1
B2 B2
B3 B3

我根据 BId 列连接这两个表 A 和 B。查询中有一个日期类型的输入,我们想要根据该参数过滤表 A 中的数据,并需要以下数据的输出。

传递给查询的输入 (input_date):2022 年 1 月 1 日

爱德 出价 日期1 日期2
1 B1 2022 年 1 月 1 日 2022年12月31日(有多个记录,但应该只出现一次)
2 B2 2021 年 1 月 1 日 2030 年 12 月 31 日
3 B3 2024 年 1 月 1 日 2030 年 12 月 31 日(这将在未来开始,但它应该会输出)

我当前正在使用以下查询,但它会提取重复的记录。

select AId, BId, Date1, Date2
from A,B
where A.BId = B.BId
and input_date >= A.Date2; -- We cant add check of Date1 as we want the record with AId '3' from table A.

但这会从 A 中提取 id 为“1”的记录的所有行。正如前面提到的,我们只想要 1 行。

我能想到的一个选择是添加不同或分组依据,但想检查是否有更好的替代方案来实现此要求。我认为随着行数的增加,DISTINCT 或 GROUP BY 会对性能产生影响。

这个问题可以用更好的方式处理吗?

PS:这些只是示例表,实际数据量较大时,表会更大。

sql performance join distinct
1个回答
0
投票

问题不清楚,因为 2022 年的输入日期不大于 2030 年的 Date2 值,尽管代码说它应该大于。它也无法告诉我们使用哪种数据库,因为不同类型的数据库之间的日期函数是不同的。

这是假设 SQL Server 的日期函数编写的。如果您使用不同的数据库,日期函数将会不同,您应该告诉我们您有什么。

它使用

row_number()
窗口函数对行进行排名,然后仅筛选每组中排名靠前的行。这允许您仍然包含可能与主要条件不匹配的行(基于“开始未来但仍应出现在输出中”注释),但编号方式使得这些行始终让位于符合条件的分区。因为问题不清楚,所以所写的排名几乎肯定是错误,但它应该为您指出一个可行的解决方案。

with numbered as (
    select A.AId, b.BId, Date1, Date2
       , row_number() over (partition by A.AId, B.BId
                                     -- prefer dates that meet the criteria
                            order by case when @input_date >= A.Date2 THEN 0 ELSE 1 END,
                                     -- and then find the value nearest the requested date
                                     abs(datediff(day, @input_date, A.Date2)) ) rn                 
    from A
    inner join B ON A.BId = B.BId
)
select AID, BId, Date1, Date2
from numbered
where rn = 1
© www.soinside.com 2019 - 2024. All rights reserved.