2

SQLSERVER 2005 では、大きなテーブルのサブセット データに対して任意の集計を実行する便利な方法として、テーブル値関数を使用しています (日付範囲などのパラメーターを渡します)。

大規模なクエリ内でこれらを結合された計算として使用していますが、クエリ プラン オプティマイザーがすべての条件でうまく機能するかどうか、または大規模なクエリでそのような計算をネスト解除する方がよいかどうか疑問に思っています。

  1. 意味がある場合、クエリ プラン オプティマイザーはテーブル値関数のネストを解除しますか?
  2. そうでない場合、手動でネストを解除することで発生するコードの重複を避けるために、何をお勧めしますか?
  3. もしそうなら、実行計画からどのようにそれを特定しますか?

コードサンプル:

create table dbo.customers (
    [key] uniqueidentifier
    , constraint pk_dbo_customers
        primary key ([key])
)
go

/* assume large amount of data */
create table dbo.point_of_sales (
    [key] uniqueidentifier
    , customer_key uniqueidentifier
    , constraint pk_dbo_point_of_sales
        primary key ([key])
)
go

create table dbo.product_ranges (
    [key] uniqueidentifier
    , constraint pk_dbo_product_ranges
        primary key ([key])
)
go

create table dbo.products (
    [key] uniqueidentifier
    , product_range_key uniqueidentifier
    , release_date datetime
    , constraint pk_dbo_products 
        primary key ([key])
    , constraint fk_dbo_products_product_range_key 
        foreign key (product_range_key) 
        references dbo.product_ranges ([key])
)
go

.

/* assume large amount of data */
create table dbo.sales_history (
    [key] uniqueidentifier
    , product_key uniqueidentifier
    , point_of_sale_key uniqueidentifier
    , accounting_date datetime
    , amount money
    , quantity int
    , constraint pk_dbo_sales_history
        primary key ([key])
    , constraint fk_dbo_sales_history_product_key
        foreign key (product_key)
        references dbo.products ([key])
    , constraint fk_dbo_sales_history_point_of_sale_key
        foreign key (point_of_sale_key)
        references dbo.point_of_sales ([key])
)
go

create function dbo.f_sales_history_..snip.._date_range
(
    @accountingdatelowerbound datetime,
         @accountingdateupperbound datetime
)
returns table as
return (
    select
                  pos.customer_key
        , sh.product_key
        , sum(sh.amount) amount
        , sum(sh.quantity) quantity
    from 
        dbo.point_of_sales pos
        inner join dbo.sales_history sh 
            on sh.point_of_sale_key = pos.[key]
    where
                  sh.accounting_date between 
                      @accountingdatelowerbound and 
                      @accountingdateupperbound
    group by
                  pos.customer_key
                  , sh.product_key
)
go

-- TODO: insert some data

-- this is a table containing a selection of product ranges
declare @selectedproductranges table([key] uniqueidentifier)

-- this is a table containing a selection of customers
declare @selectedcustomers table([key] uniqueidentifier)

declare @low datetime
    , @up datetime

-- TODO: set top query parameters

.

select
         saleshistory.customer_key
         , saleshistory.product_key
         , saleshistory.amount
         , saleshistory.quantity
from
         dbo.products p
         inner join @selectedproductranges productrangeselection 
             on p.product_range_key = productrangeselection.[key]
         inner join @selectedcustomers customerselection on 1 = 1
         inner join 
         dbo.f_sales_history_..snip.._date_range(@low, @up) saleshistory
             on saleshistory.product_key = p.[key]
             and saleshistory.customer_key = customerselection.[key]

サンプルが理にかなっていることを願っています。

ご協力ありがとうございました!

4

2 に答える 2

5

この場合、それは「インライン テーブル値関数」です。オプティマイザーは、それが有用 (またはビュー) である場合、単純に展開 (ネスト解除) します。

関数が外部クエリによって「ブラック ボックス」として扱われる場合、最も簡単な方法は、SSMS で表示される IO とプロファイラーで表示される IO を比較することです。Profler は、SSMS がキャプチャしない「ブラック ボックス」IO をキャプチャします。

Adam Mechanic によるブログ投稿(彼の本は職場の私の引き出しにあります)

于 2008-11-22T10:02:04.800 に答える
3

1)はい、あなたの構文を使用すると、そうです。ただし、条件付きロジックを含むテーブルを返す UDF を使用したとしても、そうはなりません。

3) オプティマイザは、クエリのどの部分が最適化されているかを指摘しません。これは、計画のチャンクを関数と結合したり、ビットを最適化したりするのに適していると思われるためです。

于 2008-11-22T14:14:40.237 に答える