Sql 具有函数的查询比具有子选择的相同查询耗时更长

Sql 具有函数的查询比具有子选择的相同查询耗时更长,sql,db2,query-performance,stored-functions,db2-luw,Sql,Db2,Query Performance,Stored Functions,Db2 Luw,我有一个功能为客户获得余额 创建或替换函数default1.get_balance par_customer_id小数点31,0 返回小数点31,15 语言SQL 确定性 没有外部行动 读取SQL数据 开始 申报var_余额小数31,15; 选择SUMamount 进入var_余额 来自default1.会计 其中accounting.customer\u id=par\u customer\u id 并且YEARaccounting.accounting\u date>=YEARSYSDATE

我有一个功能为客户获得余额

创建或替换函数default1.get_balance par_customer_id小数点31,0 返回小数点31,15 语言SQL 确定性 没有外部行动 读取SQL数据 开始 申报var_余额小数31,15; 选择SUMamount 进入var_余额 来自default1.会计 其中accounting.customer\u id=par\u customer\u id 并且YEARaccounting.accounting\u date>=YEARSYSDATE-3或accounting.accounting\u date为空 并且支付日期为空 和会计类型id 2 而且不存在 选择1 来自default1.accounting\u详细信息 其中accounting.id=detail.accounting\u id 和detail.paid_日期不为空; 返回var_余额; 终止 获取一个客户的余额的性能很好,但是在查询中使用函数一次获取多个客户的余额会变得非常慢

选择default1.get_balancecustomer.id,customer* 来自default1.customer 其中customer.id<1000 执行此查询需要2分钟以上

当我用subselect替换查询中的函数时,速度要快得多

选择 选择SUMamount 来自default1.会计 其中accounting.customer\u id=customer.id 并且YEARaccounting.accounting\u date>=YEARSYSDATE-3或accounting.accounting\u date为空 并且支付日期为空 和会计类型id 2 而且不存在 选择1 来自default1.accounting\u详细信息 其中accounting.id=detail.accounting\u id 和detail.paid_日期不为空, 顾客* 从…起 默认值1.客户 其中customer.id<1000 此查询大约需要8秒钟

我确实以不同的顺序多次执行了这两个查询,在运行时没有任何重大变化。所以我不认为这是一个缓存问题

为什么使用此函数的查询比使用subselect的查询花费的时间长约15倍?
在函数中有什么我可以更改以使其更快的地方吗?

我假设DB2用于LUW

函数的性能可能会受到影响,因为它使用编译后的复合语句作为其主体开始。。。终止尝试使用:开始原子。。。终止更好的是,您可能只需使用RETURN语句:

CREATE OR REPLACE FUNCTION default1.get_balance (par_customer_id DECIMAL(31, 0))
  RETURNS DECIMAL(31,15)
  LANGUAGE SQL
  NOT DETERMINISTIC
  NO EXTERNAL ACTION
  READS SQL DATA
RETURN SELECT SUM(amount)
  INTO var_balance
  FROM default1.accounting accounting 
  WHERE accounting.customer_id  = par_customer_id
    AND (YEAR(accounting.accounting_date) >= YEAR(SYSDATE)-3 or accounting.accounting_date IS NULL)
    AND paid_date IS NULL
    AND accounting_type_id <> 2
    AND NOT EXISTS (
        SELECT 1 
        FROM default1.accounting_detail detail 
        WHERE accounting.id = detail.accounting_id 
        AND detail.paid_date IS NOT NULL);
使用编译后的复合语句时,函数的每次调用都会导致从SQL数据访问引擎到执行引擎的上下文切换,而内联语句则成为查询计划本身的一部分


请注意,您不应该将此函数声明为确定性函数,因为它不是确定性函数;错误声明非确定性函数可能会导致意外结果。

谢谢!你的两个建议都有效。我将使用带有直接返回语句的版本。