web-dev-qa-db-ja.com

WITH句とサブクエリの違いは?

WITH句とサブクエリの違いは何ですか?

1. WITH table_name as ( ... )

2. select *
    from ( select curr from tableone t1
             left join tabletwo t2
               on (t1.empid = t2.empid)
         ) as temp_table
27
Hari Rao

WITH句は サブクエリファクタリング 用であり、一般的なテーブル式またはCTEとしても知られています。

WITH query_name句を使用すると、サブクエリブロックに名前を割り当てることができます。次に、query_nameを指定して、クエリ内の複数の場所でサブクエリブロックを参照できます。 Oracle Databaseは、問合せ名をインライン・ビューまたは一時表として扱うことにより、問合せを最適化します。

2番目の例では、temp_tableはインラインビューであり、一時テーブルではありません。

多くの場合、どちらを使用するかの選択は好みのスタイルになり、CTEを使用すると、特に複数レベルのサブクエリを使用すると、コードが読みやすくなります(当然のことながら、意見は異なります)。 CTE /インラインビューのみを参照する場合、パフォーマンスに違いが見られない可能性があり、オプティマイザは同じ計画になる可能性があります。

ユニオン内など、複数の場所で同じサブクエリを使用する必要がある場合に特に便利です。コードが繰り返されないようにインラインビューをCTEに引き出すことができます。これにより、オプティマイザが有益であると考える場合にコードを具体化できます。

たとえば、この不自然な例:

select curr from (
  select curr from tableone t1
  left join tabletwo t2 on (t1.empid = t2.empid)
) temp_table
where curr >= 0
union all
select -1 * curr from (
  select curr from tableone t1
  left join tabletwo t2 on (t1.empid = t2.empid)
) temp_table
where curr < 0

次のようにリファクタリングできます:

with temp_table as (
  select curr from tableone t1
  left join tabletwo t2 on (t1.empid = t2.empid)
)
select curr from temp_table
where curr >= 0
union all
select -1 * curr from temp_table
where curr < 0

サブクエリを繰り返す必要がなくなりました。繰り返されるコードが複雑になるほど、CTEを使用することがメンテナンスの観点から有益になります。そして、サブクエリが高価になるほど、CTEを使用することで得られるパフォーマンス上の利点が増えますが、通常、オプティマイザはあなたが何を考えているかをかなり理解していますとにかくやり直します。

38
Alex Poole

おそらくない。 Oracleは、クエリを実際に最適化する前に、多くの代数的変換が可能です。ほとんどの場合、両方のクエリは同じ方法で評価されます(実行プランは同じです)。

1
ibre5041

さらに、サブクエリに分析関数(LEAD/LAG/etc)が含まれていて、分析関数の結果をフィルター処理する場合は、SUBQUERYアプローチを使用して、結果を一時テーブルに挿入する必要があります。一時テーブルでフィルタリングなどを実行しますが、WITH句を使用すると、同じクエリでフィルタリング/グループ化などの結果を使用できます

;WITH temp AS
(
    SELECT 
        ID
        , StatusID
        , DateChanged
        , LEAD(StatusID,1) OVER (PARTITION BY ID ORDER BY ID, DateChanged, StatusID) NextStatusID
    FROM 
        myTable 
    WHERE 
        ID in (57,58)
)
SELECT
    ID
    , StatusID
    , DateChanged
FROM
    temp
WHERE
    temp.NextStatusID IS NULL
0
N Shah