2

在SQLSERVER 2005中,我使用表值函數作爲對大表(通過日期範圍或此類參數)的子集數據執行任意聚合的便捷方式。查詢計劃優化器是否適用於聯合/過濾的表值函數?

我在更大的查詢中使用了這些作爲連接計算,我想知道如果查詢計劃優化器在每種情況下都能很好地工作,或者如果我更好地在更大的查詢中進行這樣的計算。

  1. 是否查詢計劃優化器UNNEST 表值函數,如果它使 有意義嗎?
  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] 

我希望這個例子有意義。

非常感謝您的幫助!

回答

5

在這種情況下,它是一個「內聯表值函數」 如果優化器有用(或視圖),則它簡單地展開(取消)它。

如果該函數被外部​​查詢視爲「黑盒」,則最快的方法是比較SSMS中顯示的IO與Profiler中的IO。 Profler捕獲SSMS沒有的「黑匣子」IO。

Blog post by Adam Mechanic(他的書是我在工作的抽屜)

3

1)是的,用你的語法,它的作用。如果你碰巧使用了一個UDF,它返回了一個有條件邏輯的表,但它不會。

3)優化器不會指出它正在優化的查詢的哪部分,因爲它可能認爲適合將計劃的塊與您的函數結合起來,或優化位。