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)优化器不会指出它正在优化的查询的哪部分,因为它可能认为适合将计划的块与您的函数结合起来,或优化位。