web-dev-qa-db-ja.com

グループ化関数とウィンドウ関数を使用したテーブルスキャンの削減

私が改善しようとしているコードは次のようになります(簡単な例):

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';

次のスクリプトを使用して、これらのテーブルを再作成できます

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 );

どうすれば1結合+多分ウィンドウ関数に変更できますかcoalesce部分を書き換える方法。ただ説明すると、現在の計画では3つのtab_bスキャンが表示されています。これを1に減らします。

3
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;

このソリューションには1つのtab_b scanがありますが、sortのようにb.col_cを選択するため、COALESCEを追加します。上記の例では、このorderは、order列の値に対応するjoin conditionconstantsによって指定されたcに対応しています。順序が異なる場合は、カスタマイズされたorder byclauseを記述する必要があるため、状況はさらに複雑になります。

5
sepupic

この3つの説明を静的にしたい場合、または以下のようにしたい場合は、以下を実行できます。

  1. 一時テーブルまたは変数テーブルを作成する
  2. 一時テーブルまたは変数テーブルに値を挿入しますが、列の形式です https://stackoverflow.com/questions/15745042/efficiently-convert-rows-to-columns-in-sql-server

  3. 回答にスクリプトを記述しますが、それらの3つのLEFT JOINを削除し、一時テーブルまたは変数テーブルにCROSS JOINを実行します

  4. COALESCEコードを変更して、CROSS JOINオブジェクトから値を取得します

データベースモデルを変更して、最も必要なものを満たすこともできます。

支援するには、現在のデータベースモデルを共有してください。次のオプションで作成できます。

enter image description here

1
pncsoares
SELECT    DISTINCT a.col_a
         ,b1.col_c
FROM      tab_a a
LEFT JOIN tab_b b1
          ON a.col_a = b1.col_a
             AND b1.col_b IN ('blabla1','blabla2','blabla3');

要求に応じて1つの結合^^ IN(..)を使用してややエレガントなスタイルに編集

0
eagle275