ビューの折重ねは、ビューを参照する問合わせを、そのビューへの明示的な参照なしに書き換える、重要なクエリー リライト技術です。ビューを折り重ねることにより、ビューの結果についてのスプールを作成する必要がなくなり、結合プランナーで追加の結合順序を考慮できるようになります(最適化ルーチンの結合計画を参照)。
ビューと派生テーブルの意味は同じです。したがって、ビューに適用されるこの節の条件は、派生テーブルにも等しく適用され、ビューへの言及は、文の意味内容を変えないまま、派生テーブルへの言及として置き換えることができます。
ただし、ビューは常に折り重ねることができるわけではありません。例えば、別のテーブルに結合されている集約があるビューは、スプールする必要があります。
ビュー折重ねの例
次のビュー定義と問合わせについて考えてみます。
CREATE VIEW sales_by_product AS SELECT product_key, product_name, SUM(quantity*amount) AS total FROM sales, product WHERE sales_product_key = product_key GROUP BY product_key, product_name; SELECT product_name FROM sales_by_product WHERE total > 50000;
包含問合わせブロックから切り離してビューの結果を評価する必要はありません。このため、ビューの折重ねは、次の書き換えられた問合わせの生成時に適用できます。
SELECT product.product_name FROM sales, product WHERE sales_product_key=product.product_key GROUP BY product.product_key, product.product_name HAVING (SUM(quantity * amount))>50000;
一方、ビューをスプールすることは、ビュー定義が具体化され、主問合わせ内で単一のリレーションとして処理されることを意味します。
クエリー リライトは可能な場合はいつでもビューを折り重ねようと試みます。これは、ビューを折り重ねると、最適化ルーチンに問合わせを最適化するためのオプションがより多く提供されるためです。一方、ビューをスプールすると、そのテーブルを主問合わせで他のテーブルに直接結合することはできません。
ビューの折重ねの重要な例として、次の例に示されているようなUNION ALLビューの折重ねがあります。
SELECT * FROM sales;
この例では、saleは、年間12の販売月のうち、11のUNION ALL演算を含むビューです。
この問合わせは次のように書き換えられます。
SELECT * FROM sales1 UNION ALL SELECT * FROM sales2 UNION ALL … UNION ALL SELECT * FROM sales12;
次のビュー定義と問合わせについて考えてみます。
CREATE VIEW jan_sales AS SELECT sales_product_key, ZEROIFNULL(quantity) AS qty FROM sales1; SELECT product_name, SUM(qty) FROM product LEFT OUTER JOIN jan_sales ON product_key=sales_product_key GROUP BY product_key, product_name ;
単純に、ビューの折り重ねは、数量の値をsales1の場合のようにNULLにすることができる(その場合、ZEROIFNULL式の値は0になります)か、または製品内の行に対してsales1で一致する値がない(その場合、ZEROIFNULL式の値はNULLになります)ため不正確です。 ビューの折重ねでは、sales1の数量が最初に(外部結合の作成前に) NULLだったかどうかを追跡することによってこの問題が解決され、この追跡に基づいて正しい値が生成されます。 これは、次のように、jan_salesビューに対するクエリーに正しい書き換えを実行することができます。
SELECT product_name, SUM(CASE WHEN sales1.ROWID IS NULL THEN NULL ELSE quantity END) FROM product LEFT OUTER JOIN sales1 ON product_key=sales_product_key GROUP BY product_key, product_name;