在 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,它们附带警告。但是,根据您的示例,它们可能正是您要查找的内容。
创建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,它们附带警告。但是,根据您的示例,它们可能正是您要查找的内容。