【问题标题】:listagg alternative in OracleOracle 中的 listagg 替代方案
【发布时间】:2014-11-25 01:27:09
【问题描述】:

假设我有这个基础数据:

    DEPTNO ENAME
---------- ----------
        20 SMITH
        30 ALLEN
        30 WARD
        20 JONES
        30 MARTIN
        30 BLAKE
        10 CLARK
        20 SCOTT
        10 KING
        30 TURNER
        20 ADAMS
        30 JAMES
        20 FORD
        10 MILLER

我可以使用 listagg() 实现我想要的输出:

SELECT deptno, LISTAGG(ename, ',') WITHIN GROUP (ORDER BY ename) AS employees
FROM   emp
GROUP BY deptno;

    DEPTNO EMPLOYEES
---------- --------------------------------------------------
        10 CLARK,KING,MILLER
        20 SMITH,FORD,ADAMS,SCOTT,JONES
        30 ALLEN,BLAKE,MARTIN,TURNER,JAMES,WARD

但它超级慢。使用我的真实数据集,它使查询运行时间长 35 秒,而不是

我可以使用collect() 来加快速度吗?如果是这样,怎么做?

我也听说过用户定义的聚合函数,但这些值得吗?

【问题讨论】:

    标签: sql oracle


    【解决方案1】:

    我使用asktom 的 Tom Kyte 建议的以下用户定义函数 - 我可以接受性能(尽管它在 Oracle 8 中不起作用)。你可以试试这个吗?

    CREATE OR REPLACE TYPE t_string_agg AS OBJECT
    (
      g_string  VARCHAR2(32767),
    
      STATIC FUNCTION ODCIAggregateInitialize(sctx  IN OUT  t_string_agg)
        RETURN NUMBER,
    
      MEMBER FUNCTION ODCIAggregateIterate(self   IN OUT  t_string_agg,
                                           value  IN      VARCHAR2 )
         RETURN NUMBER,
    
      MEMBER FUNCTION ODCIAggregateTerminate(self         IN   t_string_agg,
                                             returnValue  OUT  VARCHAR2,
                                             flags        IN   NUMBER)
        RETURN NUMBER,
    
      MEMBER FUNCTION ODCIAggregateMerge(self  IN OUT  t_string_agg,
                                         ctx2  IN      t_string_agg)
        RETURN NUMBER
    );
    /
    SHOW ERRORS
    
    
    CREATE OR REPLACE TYPE BODY t_string_agg IS
      STATIC FUNCTION ODCIAggregateInitialize(sctx  IN OUT  t_string_agg)
        RETURN NUMBER IS
      BEGIN
        sctx := t_string_agg(NULL);
        RETURN ODCIConst.Success;
      END;
    
      MEMBER FUNCTION ODCIAggregateIterate(self   IN OUT  t_string_agg,
                                           value  IN      VARCHAR2 )
        RETURN NUMBER IS
      BEGIN
        SELF.g_string := self.g_string || ',' || value;
        RETURN ODCIConst.Success;
      END;
    
      MEMBER FUNCTION ODCIAggregateTerminate(self         IN   t_string_agg,
                                             returnValue  OUT  VARCHAR2,
                                             flags        IN   NUMBER)
        RETURN NUMBER IS
      BEGIN
        returnValue := RTRIM(LTRIM(SELF.g_string, ','), ',');
        RETURN ODCIConst.Success;
      END;
    
      MEMBER FUNCTION ODCIAggregateMerge(self  IN OUT  t_string_agg,
                                         ctx2  IN      t_string_agg)
        RETURN NUMBER IS
      BEGIN
        SELF.g_string := SELF.g_string || ',' || ctx2.g_string;
        RETURN ODCIConst.Success;
      END;
    END;
    /
    SHOW ERRORS
    
    
    CREATE OR REPLACE FUNCTION string_agg (p_input VARCHAR2)
    RETURN VARCHAR2
    PARALLEL_ENABLE AGGREGATE USING t_string_agg;
    /
    SHOW ERRORS
    

    应用,

    COLUMN employees FORMAT A50
    
    SELECT deptno, string_agg(ename) AS employees
    FROM   emp
    GROUP BY deptno;
    
        DEPTNO EMPLOYEES
    ---------- --------------------------------------------------
            10 CLARK,KING,MILLER
            20 SMITH,FORD,ADAMS,SCOTT,JONES
            30 ALLEN,BLAKE,MARTIN,TURNER,JAMES,WARD
    
    3 rows selected.
    

    【讨论】:

    • 很难相信用户定义的聚合函数会比 Oracle 的内置函数更快。你有这方面的基准吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-15
    相关资源
    最近更新 更多