【问题标题】:Fast search in collection type column在集合类型列中快速搜索
【发布时间】:2023-03-15 17:25:01
【问题描述】:

创建集合类型:

CREATE TYPE nums_list AS TABLE OF NUMBER;

用集合类型的列创建表(嵌套表列):

CREATE TABLE test1 (
        num NUMBER,
        tagged nums_list
)
NESTED TABLE tagged STORE AS mytest_tagged_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;

然后运行查询以查找集合类型中的元素:

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

此查询运行缓慢,执行时间约为 7-8 秒。

问题:如何加快执行时间?可能是索引?但是我不明白如何为嵌套表列使用索引。

附:我尝试使用循环检查 PL/SQL 块中的每一行,使用游标,然后将结果作为流水线表函数返回,但这比直接查询要慢。

【问题讨论】:

  • 在您编写示例时,我认为从 600,000 开始的所有行都将在列表中具有数字 8。这意味着,您的查询将返回 400,000(在 1,000,000 行中)。嵌套表与否,这不是索引将有很大帮助的查询类型。这是您在示例中的意图,让这么多行满足查询吗?
  • @Matthew -- 是的,正好 400,001 行返回此查询。数据这么大吗?
  • 它本身并不是“大”。就是它占表中总行数的很大比例。在这种情况下,读取整个表(即“全表扫描”)来执行搜索比 400,000 次索引查找更有效。全扫描可以在单个 I/O 中读取许多表块,而索引查找将需要 3-4 个 I/O每行。对于这样一个狭窄的表,全表扫描可能需要不到 100,000 次 I/O(粗略猜测),而带有索引的嵌套循环连接可能需要超过 100 万次 I/O。
  • 有什么理由需要存储一个集合吗?一般来说,将其存储为子表会更加传统,这样子表就会有很多很多的性能调整选项。
  • @JustinCave -- 唯一的原因是我有行(项目),它可能被 10 个不同的标签标记,所以如果将这些存储在子表中,每个项目将有 10 行(10此项目的每个标签的行)。在集合的情况下,单个项目只有一行,但你是对的,另一张表似乎更好。此外,从 Matthew 的回答来看,无论如何都发生了“取消嵌套”集合

标签: oracle plsql oracle12c


【解决方案1】:

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

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

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

所以,问题不是“我怎样才能让 Oracle 对我的嵌套表使用索引”?我怎样才能让 Oracle 到?

由于您的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 不直接等同于嵌套表,它们带有警告。但是,根据您的示例,它们可能是您正在寻找的。​​p>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-05
    • 1970-01-01
    • 2022-01-24
    • 1970-01-01
    • 1970-01-01
    • 2012-04-13
    相关资源
    最近更新 更多