使用 group by 和 window 函数减少表扫描

Mic*_*vko 3 sql-server window-functions sql-server-2016

有一个我正在尝试改进的代码,如下所示(简单示例):

SELECT    DISTINCT a.col_a
         ,COALESCE(b1.col_c, b2.col_c, b3.col_c)
FROM      tab_a a
LEFT JOIN tab_b b1
          ON a.col_a = b1.col_a
             AND b1.col_b = 'blabla1'
LEFT JOIN tab_b b2
          ON a.col_a = b2.col_a
             AND b2.col_b = 'blabla2'
LEFT JOIN tab_b b3
          ON a.col_a = b3.col_a
             AND b3.col_b = 'blabla3';
Run Code Online (Sandbox Code Playgroud)

您可以使用以下脚本重新创建这些表

CREATE TABLE tab_a(col_a int)
CREATE TABLE tab_b(col_a INT, col_b VARCHAR(10), col_c INT)

INSERT INTO dbo.tab_a ( col_a ) VALUES ( 1 ), ( 2 ), ( 3 );

INSERT INTO dbo.tab_b ( col_a
                       ,col_b
                       ,col_c )
VALUES ( 1, 'blabla1', 1 )
      ,( 1, 'blabla2', 3 )
      ,( 1, 'blabla2', 5 )
      ,( 2, 'blabla2', NULL )
      ,( 2, 'blabla3', 5 );
Run Code Online (Sandbox Code Playgroud)

如何将其更改为 1 join + 也许是窗口函数以及如何重写合并部分。只是为了解释一下,当前计划显示 3 tab_b 扫描,我想将其减少到 1。

sep*_*pic 5

SELECT    DISTINCT a.col_a
         ,b.col_c
FROM      tab_a a
outer apply (select top 1 b.col_c 
             from tab_b b
             where ((a.col_a = b.col_a
                     AND b.col_b = 'blabla1' )
                  or (a.col_a = b.col_a
                     AND b.col_b = 'blabla2')
                  or (a.col_a = b.col_a
                     AND b.col_b = 'blabla3'))
                  and b.col_c is not null
            order by b.col_b)b;
Run Code Online (Sandbox Code Playgroud)

此解决方案有 1 tab_bscan但添加sort是因为您想b.col_cCOALESCE. 在上面的例子中,这order对应于orderyour constantsin给出的join condition对应于c列的值。如果订单应该不同,事情会更复杂,因为您应该编写自定义order by条款。

  • @MichaelCherevko 您可以发布一个不同的问题,其中包含额外的要求以及更大的示例和预期结果 (2认同)