性能调优复杂 SQL 连接

Posted

技术标签:

【中文标题】性能调优复杂 SQL 连接【英文标题】:Performance tuning complex SQL join 【发布时间】:2020-09-25 12:20:59 【问题描述】:

我正在尝试在 2 个表上进行连接。

表A

| date | var |
+------+-----+
| 1    | a   |
| 2    | b   |
| 3    | e   |
| 4    | c   |
| 5    | b   |

表B

| date | var |
+------+-----+
| 1    | a   |
| 2    | b   |
| 3    | c   |
| 3    | d   |

我想进行内部连接,以便日期和 var 匹配,或者如果 tableA 中的日期大于 tableB 中的日期,则仅在 tableA 中的 var 与 tableB 中的 var 匹配,其中 tableB 中的日期为最大值。

输出表应该是:

| date | var |
+------+-----+
| 1    | a   |
| 2    | b   |
| 4    | c   |

这是我想出的——但速度很慢:

select a.*
from tablea a
inner join tableb b on (a.var = b.var and a.date = b.date)
                    or (a.date > (select max(date) from tableb b) 
                        and b.var in (select var from tableb having max(date)=date))

【问题讨论】:

用您正在使用的数据库标记您的问题。此外,显示您想要的结果。此外,您只是从a 中选择列,因此join 似乎没有必要。 列句号,在tableb中? @jarlh Ups。类型。现已更正 @GordonLinoff 我正在尝试删除一些不匹配的列。我添加了输出表示例。希望这会让它更清楚。 请解释结果集中最后两行的逻辑:(3,e)和(4,c) 【参考方案1】:

像这样加入表格:

SELECT a.*
FROM TableA a INNER JOIN TableB b 
ON a.var = b.var AND b.date = (SELECT MAX(date) FROM TableB WHERE a.date >= date)

请参阅demo。 结果:

> date | var
> ---: | :--
>    1 | a  
>    2 | b  
>    4 | c  

【讨论】:

如果这是你的意思,那么是的。但是您原来的 sql 暗示了一些不同的东西,请参阅下面的答案。它会为您提供的数据集返回相同的结果,但会为不同的数据集返回不同的结果。您应该澄清您的规范以表明您的意思。【参考方案2】:

如果不知道确切的架构(包括索引),就很难预测性能。总的来说,我敢打赌下面的查询会更高效。

DECLARE @a TABLE(date INT, var NVARCHAR(1))
INSERT @a VALUES(1,'a'),(2,'b'),(3,'e'),(4,'c'), (5,'b')

DECLARE @b TABLE(date INT, var NVARCHAR(1))
INSERT @b VALUES(1,'a'),(2,'b'),(3,'c'),(3,'d')

;
WITH b AS
(
    select * from(
        select var,date,dateRankReveresed = rank() OVER(ORDER BY date DESC)
        from @b 
    )as x
)


select a.*
from
    @a a
    inner join b b on a.var=b.var 
                    and 
                    ((a.date=b.date) 
                    or 
                    ((a.date > b.date and b.dateRankReveresed=1)))

编辑:在这种情况下,请使用 rank 而不是 row_number,因为您需要 dups 的关系。

【讨论】:

【参考方案3】:

您的 sql 在 mysql 中不起作用,但我将其更改为:

 select a.*
 from TableA a
 inner join TableB b on (a.var = b.var and a.dat = b.dat) OR (a.dat > (select 
 max(dat) from TableB) 
                    and b.var in (select var from TableB where TableB.dat= 
 (select max(dat) from TableB)));

但这样我会得到更多的结果。

'1', 'a'
'2', 'b'
'4', 'c'
'4', 'c'
'5', 'b'
'5', 'b'

相反,我认为你想要:

select a.*
from TableA a
where (a.dat > (select max(dat) from TableB) 
        and a.var in (select var from TableB 
                  where TableB.dat=(select max(dat) from TableB)))
union select a.* from TableA a inner join TableB b where a.var=b.var and 
a.dat=b.dat; 

【讨论】:

以上是关于性能调优复杂 SQL 连接的主要内容,如果未能解决你的问题,请参考以下文章

性能调优 SQL - 如何?

性能测试-性能调优之一

SQL语句调优

mysql性能调优

MySQL性能调优(软调优)

MySQL性能调优