在 collection 类型列中快速搜索

Fast search in collection type column

创建collection类型:

CREATE TYPE nums_list AS TABLE OF NUMBER;

使用 collection 类型的列(嵌套 table 列)创建 table:

CREATE TABLE test1 (
        num NUMBER,
        tagged nums_list
)
NESTED TABLE tagged STORE AS mytest_tagged_table;

在 table 中插入 100 万行:

DECLARE 
    tagg_value nums_list := nums_list(3,4,5);
BEGIN
    for i in 1..1000000 loop
          if i = 600000 then
              tagg_value := nums_list(7,8);
          end if;

          INSERT INTO test1
          (num, tagged)
          VALUES
          (i, tagg_value);
    end loop;
END;

然后 运行 查询 collection 中的搜索元素类型:

    select count(*) from test1 where 8 member of tagged;

这个查询慢运行s,执行时间大约7-8秒。

问:如何加快执行时间?可能是索引?但是我不知道如何为嵌套的 table 列使用索引。

P.S。我尝试使用循环检查 PL/SQL 块中的每一行,使用游标然后 return 结果作为流水线 table 函数,但这比直接查询慢。

如果您对示例中的此查询执行 EXPLAIN PLAN

select count(*) from test1 where 8 member of tagged;

...您会看到 Oracle 可能 mytest_tagged_table 上使用(系统生成的)索引来帮助提高性能。仍然需要这么长时间的原因是 400,000 次索引查找实际上 比读取整个 table.

效率低

所以,问题不是 "how can I get Oracle to use an index with my nested table"?这是我怎样才能让 Oracle not 到?

您有一个替代方法,因为您的 tagged 列表看起来很小,是使用 VARRAY。这些可以内联存储以获得更好的性能,尽管关联的语法不那么干净。

这是您的示例,针对 VARRAY:

进行了修改
CREATE NONEDITIONABLE TYPE nums_varray AS VARRAY(10) OF NUMBER;

CREATE TABLE test2 (
        num NUMBER,
        tagged nums_varray
);

INSERT INTO test2
SELECT rownum,
       case when rownum < 600000 then new nums_varray(3,4,5) else new nums_varray(7,8) end
FROM   dual
connect by rownum <= 1000000;


select count(*) from test2 
where exists ( 
   SELECT '8 in list' 
   FROM TABLE(tagged) 
   WHERE column_value = 8);

在我的系统上,这只需要 3,600 个缓冲区就可以到达 运行 —— 而您的示例查询需要 2.1 百万 个缓冲区。相应地,它也 运行 快得多。

VARRAYS 不直接等同于嵌套的 table,它们附带警告。但是,根据您的示例,它们可能正是您要查找的内容。