Sql Join on User Defined Function:如何优化

时间:2012-03-01 11:16:21

标签: sql optimization join user-defined-functions

我正在尝试优化数据库中的查询。该查询类似于以下内容:

select * from Account 
   inner join udf_Account('user') udfAccount 
   on Account.Id = udfAccount.AccountId

实际上,真正的查询要长得多,但最重要的一点是它包含一些用户定义函数(udf)的内部联接,这取决于用户ID。 (因此,这是在查询评估期间不会更改的常量参数。)

由于数据量很大,我的查询在生产数据库上大约需要20秒,这是不可接受的。

我已经看到,通过将函数的结果存储在临时表中并在查询中使用这些表会减少查询的持续时间。

我问的是以下问题:

  1. 我可以避开临时表吗?这不是告诉sql该函数只能被评估一次的方法吗?使用临时表会意味着我的代码中有一些重要的变化,这就是为什么如果我有另一个解决方案,我会很高兴。

  2. 还有其他方法可以优化我的查询吗?

2 个答案:

答案 0 :(得分:4)

在SQL Server中,如果您的函数是Inline而不是Multi-Statement,则SQL Server会将tham(类似宏)解释为您的查询。就像它们在您的主查询中成为子查询一样。

这在理论上允许优化者制定“更好”的执行计划。

例如;如果您加入的字段直接从其源表派生,则应该使这些字段上的索引可用。

如果不查看整个查询和各个函数,您的语法就已经处于良好的位置。接下来要看的是存在的索引,并且目标是索引搜索而不是表扫描或索引扫描。

(这有点过于简单,但它是查询优化的一个良好开端,这是一个巨大的主题。)


另一个选择是使用CROSS APPLY和内联表值函数 (在SQL Server 2005及更高版本中可用)

这允许查询中的表的值用作函数的参数。同样,只要函数是内联函数,SQL Server在构建执行计划时就会内联函数。

一个例子可能是......

SELECT
  Account.AccountID,
  subAccount.AccountID        AS SubAccountID,
  Balance.currentAvailable    AS SubAccountBalance
FROM
  Account
CROSS APPLY
  dbo.getSubAccounts('User', Account.AccountID) AS SubAccount
CROSS APPLY
  dbo.getCurrentBalance(SubAccount.AccountID)   AS Balance
WHERE
  Account.AccountID = 1234

答案 1 :(得分:1)

我相信你想要定义mysql所谓的'确定性"功能。根据您的SQL风格,这将具有不同的语法。但最终最大的优化是根本不使用函数,而只需在用户表中添加一个帐户列。