改进/优化SQL Server中的LEFT JOIN

时间:2013-01-19 00:59:23

标签: sql sql-server sql-server-2008

我有一个相当长的(10个表,每个约60k记录)查询,所有这些表都使用左连接连接,因为它们可以包含空值(所有这些)。

我看到了巨大的性能损失,我将其跟踪到这段代码。

SELECT * 
FROM MAIN_TABLE d 
LEFT JOIN INSURANCES i on i.IMREDEM_CODE = d.IMREDEM_CODE 
                      and i.INS_TERMINATIONDATE IS NULL 
                      and INS_RANK = 0
                      and i.IMREINS_CODE = (SELECT TOP 1 IMREINS_CODE 
                                              from INSURANCES i2
                                             WHERE i2.IMREDEM_CODE = i.IMREDEM_CODE 
                                               and i2.INS_TERMINATIONDATE IS NULL 
                                               and i2.INS_RANK = 0
                                          ORDER BY TAG_SYSTEMDATE DESC)

基本上我需要做的是保险表可能包含0个或多个记录,因为当他们更新保险时,它会执行插入而不是更新以用于审计目的。所以我必须在左边的连接上加入桌子两次。此外,我需要为主要和次要保险两次执行此查询(主要是rank = 0,secondary是rank = 1.IMREDEM_CODE是D表的PK和i表的FK。

答案就在这里

left join INSURANCES i on i.IMREDEM_CODE = d.IMREDEM_CODE 
and i.IMREINS_CODE = (SELECT max(imreins_code) FROM INSURANCES i2  WHERE i2.IMREDEM_CODE = i.IMREDEM_CODE and i2.INS_TERMINATIONDATE IS NULL and i2.INS_RANK = 0)

2 个答案:

答案 0 :(得分:2)

虽然我确信你可以进一步优化这一点,但我已经快速尝试了。您的执行计划将执行3次表扫描。您可以尝试将其减少到2:

SELECT *
FROM Main_Table d
    LEFT JOIN 
        (SELECT TOP 1 *
         FROM Insurances 
         WHERE INS_TERMINATIONDATE IS NULL 
             AND INS_RANK = 0
         ORDER BY TAG_SYSTEMDATE DESC) i on i.IMREDEM_CODE = d.IMREDEM_CODE;

可能有比TOP 1和Order By更好的方法,但是我已经厌倦了,现在想不到它。无论哪种方式,这肯定更有效。

以下是包含两组查询的SQL Fiddle。您可以在每个中看到执行计划。

祝你好运。

答案 1 :(得分:1)

我相信以下内容会给你完全相同但更快的结果;

  SELECT * 
     FROM MAIN_TABLE d 
LEFT JOIN INSURANCES i on i.IMREDEM_CODE = d.IMREDEM_CODE 
                      and i.IMREINS_CODE = select max(i.imreins_code) from INSURANCES
                      and i.INS_TERMINATIONDATE IS NULL
                      and i.INS_RANK = 0