理解 Oracle 函数中的 'BULK COLLECT'

Understanding 'BULK COLLECT' in Oracle Function

给定以下 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

或者,换句话说,是否有任何我可以添加到这一行或其他地方以加快查找速度的东西 - 也许是索引?

您所能做的就是将单个 select 与 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(或从 table 引用的其他列)上添加索引将有助于加快查询速度

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

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

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

如果您 运行 遇到内存问题,您可以使用 BULK COLLECTLIMIT 子句来获取记录的小子集并使用流水线函数实现将它们吐出。但是你真的应该先看看填充查询的性能。

So looking up a value form the array is O(n)?

循环遍历集合是线性的(充其量)。使用 SQL 限制结果集通常比使用 select 所有内容并在循环中过滤结果集更有效。 SQL 在处理集时效率很高。换句话说,.

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

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;