用户定义函数上的 Sql Join:如何优化
Posted
技术标签:
【中文标题】用户定义函数上的 Sql Join:如何优化【英文标题】:Sql Join on User Defined Function: how to optimize 【发布时间】:2012-03-01 11:16:20 【问题描述】:我正在尝试优化数据库中的查询。该查询类似于以下内容:
select * from Account
inner join udf_Account('user') udfAccount
on Account.Id = udfAccount.AccountId
实际上真正的查询要长得多,但最重要的一点是它包含一些用户定义函数 (udf) 的内部连接,这些函数取决于用户 ID。 (所以这是一个常量参数,在查询评估期间不会改变)。
由于数据量大,我的查询在生产数据库上大约需要 20 秒,这是不可接受的。
我已经看到,通过将函数的结果存储在临时表中并在查询中使用这些表,可以大大减少查询的持续时间。
我在问以下问题:
我可以避免使用临时表吗?这不是告诉sql函数只能评估一次的方法吗?使用临时表意味着我的代码会发生一些重要的变化,这就是为什么如果我有另一个解决方案我会很高兴的原因。
还有其他方法可以优化我的查询吗?
【问题讨论】:
我忘了补充一点,我的函数都是“内联表值”函数。 【参考方案1】:在 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
【讨论】:
【参考方案2】:我相信您想定义 mysql 所谓的“确定性”函数。根据您的 SQL 风格,这将具有不同的语法。但最终最大的优化是根本不使用函数,而只是在用户表中添加一个帐户列。
【讨论】:
抱歉,我忘记补充说我使用的是 MS SQL Server 2008。功能取决于用户,尤其是他/她的权限/角色。据我所知,每次查询完成时,都需要重新计算该函数。以上是关于用户定义函数上的 Sql Join:如何优化的主要内容,如果未能解决你的问题,请参考以下文章
有用的 Amazon Redshift SQL 用户定义函数的任何示例?
如何获取用户在 SQL 或 Ruby 中评论的页面上的最新评论?