SQL Server 2008 中用户定义的排名/分析函数
Posted
技术标签:
【中文标题】SQL Server 2008 中用户定义的排名/分析函数【英文标题】:User-defined ranking / analytic functions in SQL Server 2008 【发布时间】:2009-11-16 04:19:18 【问题描述】:我正在计划将数据仓库迁移到 SQL Server 2008,并尝试想办法在 SQL Server 2008 中从 Oracle 复制 LAG、LEAD、FIRST_VALUE 和 LAST_VALUE 分析函数。它们不包含在 SQL Server 2008 中,尽管窗口分析函数的基本机制是(例如 ROW_NUMBER、RANK 和 DENSE_RANK 都存在)。
对于这些函数,可以通过创建一个子查询来实现相同的功能,该子查询使用 ROW_NUMBER 为每一行分配一个数字,然后对该查询进行自联接以查找具有附近行号的相关行(对于 LAG 和 LEAD) ,或行号 1(对于 FIRST_VALUE)。
我希望执行自联接会降低操作的效率:但我还没有 SQL Server 来测试这一点。因此,在没有实际评估性能的情况下,我想知道是否有更好的解决方法来避免自联接。
查看user-defined aggregate functions 的文档,可以想象相同的代码结构可以用于提供用户定义的分析函数。
所以我的问题是:您可以在用户定义的聚合函数之后添加一个 OVER() 子句以将其作为分析函数调用吗?
如果是这样,是否每行调用一次 Terminate() 方法?是否需要任何特别的东西来确保按照 OVER() 子句中指定的顺序将行发送到您的 UDF?
【问题讨论】:
【参考方案1】:我会使用自联接而不是 udf。
您正在查看使用表访问的标量 UDFS,它几乎总是会导致性能不佳(它是游标)。否则,您可能会使用 APPLY,但这也是逐行的。
此外,Oracle 函数不是聚合函数。用户定义的聚合仍然需要对结果集进行相同的处理。
请记住,无论如何,Oracle 在内部仍然需要逐行处理来计算值。
因此,FIRST_VALUE 的 SQL Server 2005+ 示例(未测试)使用自联接。
注意交叉连接以解耦 FIRST_VALUE 和其余 2,因为结果集没有关系。如果您使用 UDF 或用户定义的 agg,那么很可能您必须从第一个结果集中的每行一遍又一遍地计算 FIRST_VALUE。
;WITH CTE AS
(
SELECT
department_id, last_name, salary,
ROW_NUMBER() OVER (ORDER BY salary) AS ranking
FROM employees
WHERE department_id = 90
)
SELECT
c1.department_id, c1.last_name, c1.salary,
c2.last_name as Poorest
FROM
CTE c1
CROSS JOIN
(SELECT last_name FROM CTE WHERE Ranking = 1) c2
ORDER BY
c1.employee_id
【讨论】:
很公平:我希望从聚合 UDF 示例的设计中,优化器可能有更多可用选项,这些选项可能会比直接游标带来更好的性能。 Oracle 可能确实对分析函数进行了逐行处理,但它能够在一次遍历数据(排序之后)中完成此操作,这通常比等效的自连接更好。如果每行中有多个函数,您认为 UDF 是否会获得任何优势,这会导致许多自联接? 您可能可以在一个自联接中服务多个输出。在我的示例中,您可以为薪水 DESC 设置一个额外的 CTE 列,并且也可以执行 LAST_VALUE。多个 udf 会比单个 UDF 更糟糕。【参考方案2】:在 SQL Server 中,分析是 SSAS 的一部分;你会在那里找到 FirstNonEmpty、LastNonEmpty、FirstChild、LastChild。它包含在标准版和企业版 SQL Server 中; see here。也就是说,如果您想构建多维数据集。
【讨论】:
以上是关于SQL Server 2008 中用户定义的排名/分析函数的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server 2008R2 用户定义函数(表值)性能
将用户定义表中的日期值传递给 SQL Server 2008 存储过程
SQL Server 2008 - 返回连接条目和“无法绑定多部分标识符”错误的用户定义函数
SQL Server 2008 - UDF 参数类型和返回类型
用户“sa”登录失败。用户未与受信任的 SQL Server 连接关联。 (Microsoft SQL Server,错误:18452)在 sql 2008 中