了解Oracle Function中的“批量收集”

时间:2018-08-02 12:39:02

标签: sql oracle performance plsql bulk-operations

提供以下Oracle功能:

CREATE or REPLACE FUNCTION foo(id NUMBER, category VARCHAR) RETURN CHAR IS

TYPE MY_ARRAY2 IS TABLE OF NUMBER;
MY_ARRAY MY_ARRAY2;

BEGIN

   SELECT my_id BULK COLLECT INTO my_array FROM my_table

   RETURN (
            CASE WHEN category = 'FOO' AND (id member of MY_ARRAY)
              THEN 'Y'
              ELSE 'N'
            END
   );
END;

查找的本质是什么

   SELECT my_id BULK COLLECT INTO my_array FROM my_table

或者换句话说,有什么我可以添加到此行或其他地方以加快查找速度的东西-也许是索引吗?

3 个答案:

答案 0 :(得分:3)

您所能做的就是对MAXCOUNT使用单个选择

AS
..
..

v_retval VARCHAR2(10);


SELECT MAX(CASE 
            WHEN category = 'FOO'
                AND id = my_id 
                THEN 'Y'
            ELSE 'N'
            END) INTO v_retval
FROM my_table;
RETURN v_retval;

这取决于字符串“ Y”>“ N”的事实。您也可以使用COUNT(CASE ..和其他情况下的where count > 1 THEN 'Y'

在id(或表中引用的其他列)上添加索引将有助于加快查询速度

请注意,最好使用p_idp_category形式的过程参数以避免冲突

答案 1 :(得分:2)

BULK COLLECT只是一种使用多行结果集填充PL / SQL集合(数组)的方法。如果没有它,我们将只能使用单行填充标量值。

就性能而言,最大的影响实际上是查询的效率,您可以按照通常的方式进行调整。否则,BULK COLLECT的性能在很大程度上是透明的=除非您选择大量的行。这很重要,因为集合驻留在会话级内存中,因此,如果您的PGA配置不正确,那么非常大的集合(许多行,许多列)可能导致分页(写入磁盘)。

如果遇到内存问题,可以将BULK COLLECTLIMIT子句一起使用,以获取记录的一小部分,并使用流水线函数实现将其吐出。但是您确实应该首先查看填充查询的性能。

  

那么从数组中查找一个值是O(n)?

在一个集合中循环是线性的(最好)。使用SQL限制结果集通常比选择所有内容并在循环中过滤结果集更有效。 SQL在处理集合方面非常高效。换句话说,Kaushik's solution

答案 2 :(得分:0)

这将更具可读性。确保可以将索引放在表的id字段中。 如果id不是主键(即可能有重复项),请在ROWNUM = 1子句中使用WHERE

FUNCTION foo(p_id NUMBER, p_category VARCHAR) RETURN CHAR IS
n NUMBER;
BEGIN
    SELECT id INTO n FROM table WHERE id = p_id AND p_category = 'FOO';
    RETURN 'Y';
EXCEPTION WHEN OTHERS THEN
    RETURN 'N';
END;