简体   繁体   English

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

[英]Understanding 'BULK COLLECT' in Oracle Function

Given the following 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;

What's the nature of the lookup of: 查找的本质是什么:

  SELECT my_id BULK COLLECT INTO my_array FROM my_table 

Or, put differently, is there anything that I can add to this line or elsewhere to speed up the look-up - perhaps an index? 或者换句话说,有什么我可以添加到此行或其他地方以加快查找速度的方法-也许是索引?

All you could do is to use a single select with MAX or COUNT 您所能做的就是对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;

This relies on the fact that string "Y" > "N" . 这取决于字符串“ Y”>“ N”的事实。 You may also use COUNT(CASE .. and another case where count > 1 THEN 'Y' 您也可以使用COUNT(CASE ..和另外一种情况where count > 1 THEN 'Y'

Adding an index on id (or other columns referred from the table ) will help to speed up the query 在id(或表中引用的其他列)上添加索引将有助于加快查询速度

Note that it is better to use procedure arguments of the form p_id and p_category to avoid conflict 请注意,最好使用格式为p_idp_category过程参数以避免冲突

BULK COLLECT is simply a method for populating an PL/SQL collection (array) with a result set of multiple rows. BULK COLLECT只是一种使用多行结果集填充PL / SQL集合(数组)的方法。 Without it we're restricted to populating a scalar value with a single row. 没有它,我们只能使用单行填充标量值。

In terms of performance, the biggest impact is actually the efficiency of the query, which you can tune in the usual fashion. 在性能方面,最大的影响实际上是查询的效率,您可以按照通常的方式进行调整。 Otherwise, the performance of BULK COLLECT is largely transparent = unless you're selecting lots (thousands) of rows. 否则, BULK COLLECT的性能在很大程度上是透明的=除非您选择大量(数千)行。 That matters because collections reside in session level memory, so very big collections (lots of rows, many columns) can lead to paging (writing to disk) if your PGA is not configured well. 这很重要,因为集合驻留在会话级内存中,因此,如果您的PGA配置不正确,那么非常大的集合(许多行,许多列)可能导致分页(写入磁盘)。

If you are running into memory problems you could use BULK COLLECT with the LIMIT clause to fetch small subsets of the records and spit them out using a pipelined function implementation. 如果遇到内存问题,可以将BULK COLLECTLIMIT子句一起使用,以获取记录的小子集,并使用流水线函数实现将其吐出。 But you really should look at the performance of the populating query first. 但是,您确实应该首先查看填充查询的性能。

So looking up a value form the array is O(n)? 那么从数组中查找一个值是O(n)吗?

Looping through a collection is linear (at best). 在一个集合中循环是线性的(最好)。 It's usually way more efficient to restrict a result set using SQL than to select everything and filter the result set in a loop. 使用SQL限制结果集通常比选择所有内容并在循环中过滤结果集更有效。 SQL is highly efficient at processing sets. SQL在处理集合方面非常高效。 In other words, Kaushik's solution . 换句话说, Kaushik的解决方案

This would be way more readable. 这将更具可读性。 Sure you could put index on id field in your table. 确保您可以在表的id字段中放置索引。 If id is not a primary key (ie there may be duplicates), use ROWNUM = 1 in WHERE clause. 如果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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM