作为一个额外的观察,不是嵌套表本身太大或使用太多内存。使用异常处理程序,您可以看到您的函数没有抛出错误。您可以在匿名块中填充相同的内容:
DECLARE
ret_table nums_list := nums_list();
BEGIN
FOR i IN 1..4555555 LOOP
ret_table.EXTEND;
ret_table(i) := i;
END LOOP;
dbms_output.put_line(ret_table.count);
END;
/
anonymous block completed
4555555
你也可以从一个块中调用你的函数:
DECLARE
ret_table nums_list;
BEGIN
ret_table := generate_series(1,4555555);
dbms_output.put_line(ret_table.count);
END;
/
anonymous block completed
4555555
仅当您将其用作表集合表达式时才会出现错误:
SQL Error: ORA-22813: operand value exceeds system limits
22813. 00000 - "operand value exceeds system limits"
*Cause: Object or Collection value was too large. The size of the value
might have exceeded 30k in a SORT context, or the size might be
too big for available memory.
*Action: Choose another value and retry the operation.
原因文本是指 SORT 上下文,并且您的查询正在进行排序:
------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 2 | 29 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 2 | | |
| 2 | COLLECTION ITERATOR PICKLER FETCH| GENERATE_SERIES | 8168 | 16336 | 29 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------
正如@a_horse_with_no_name 建议的那样,您可以通过使函数流水线化来避免该问题:
CREATE OR REPLACE FUNCTION generate_series(from_n NUMBER, to_n NUMBER)
RETURN nums_list PIPELINED AS
BEGIN
FOR i IN from_n..to_n LOOP
PIPE ROW (i);
END LOOP;
RETURN;
END;
/
SELECT count(*) FROM TABLE ( generate_series(1,4555555) );
COUNT(*)
----------
4555555
仍然可以,SORT AGGREGATE
但它似乎不再介意。不太确定为什么在这两种情况下都会这样做;也许其他人将能够解释它在做什么。(顺便说一句,我在 11gR2 实例中执行此操作;我没有 12c 实例来验证行为是否相同,但您的症状表明会如此)。或者,问题可能不是 SORT 上下文,而是可用内存。在我的环境中,您的版本似乎始终可以使用多达 4177918 个元素 - 这似乎不是一个重要的数字,所以可能与环境有关?
但这取决于您打算如何使用该集合;从 PL/SQL 上下文来看,您的原始版本可能更合适。