理解 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 与 MAX
或 COUNT
一起使用
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_id
和 p_category
形式的过程参数以避免冲突
BULK COLLECT
只是一种用多行结果集填充 PL/SQL 集合(数组)的方法。没有它,我们只能用一行来填充标量值。
在性能方面,最大的影响实际上是查询的效率,您可以按照通常的方式进行调优。否则,BULK COLLECT
的性能在很大程度上是透明的 = 除非您 select 处理大量(数千)行。这很重要,因为集合驻留在会话级内存中,因此如果您的 PGA 配置不当,非常大的集合(很多行,很多列)可能会导致分页(写入磁盘)。
如果您 运行 遇到内存问题,您可以使用 BULK COLLECT
和 LIMIT
子句来获取记录的小子集并使用流水线函数实现将它们吐出。但是你真的应该先看看填充查询的性能。
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;
给定以下 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 与 MAX
或 COUNT
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_id
和 p_category
形式的过程参数以避免冲突
BULK COLLECT
只是一种用多行结果集填充 PL/SQL 集合(数组)的方法。没有它,我们只能用一行来填充标量值。
在性能方面,最大的影响实际上是查询的效率,您可以按照通常的方式进行调优。否则,BULK COLLECT
的性能在很大程度上是透明的 = 除非您 select 处理大量(数千)行。这很重要,因为集合驻留在会话级内存中,因此如果您的 PGA 配置不当,非常大的集合(很多行,很多列)可能会导致分页(写入磁盘)。
如果您 运行 遇到内存问题,您可以使用 BULK COLLECT
和 LIMIT
子句来获取记录的小子集并使用流水线函数实现将它们吐出。但是你真的应该先看看填充查询的性能。
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;