Oracle:PL/SQL 中查看值是否存在的最快方法:列表、VARRAY 或临时表

gfr*_*ius 4 oracle plsql

更新如果您想查看很长的原始问题,请查看编辑。这是问题的更清晰的简短版本......

我需要查看GroupA(并非总是如此GroupA,这会改变每次循环迭代)是否存在于 200 个左右的组的 [list,varray,temp table,whatever] 中。我如何存储这 200 个组完全由我控制。但是我想将它们存储在一个结构中,该结构适合于进行最快的“存在”检查,因为我将不得不在循环中针对不同的值(并非总是GroupA)多次检查此列表。那么什么是 PL/SQL 中最快的,检查一个列表......

IF 'GroupA' IN ('GroupA','GroupB') THEN...

或使用 MEMBER OF ... 检查 VARRAY

IF 'GroupA' MEMBER OF myGroups THEN
Run Code Online (Sandbox Code Playgroud)

或以这种方式检查 VARRAY...

FOR i IN myGroups.FIRST .. myGroups.LAST
LOOP
    IF myGroups(i) = 'GroupA' THEN
        v_found := TRUE;
        EXIT;
    END IF;
END LOOP;
Run Code Online (Sandbox Code Playgroud)

或检查关联数组... will test this tomorrow

更新:来自每个人的建议的最终测试结果 谢谢大家。我运行了这些测试,循环了 1000 万次,使用 a 的逗号分隔字符串LIKE似乎是最快的,所以我想这些点必须归于@Brian McGinity(时间在下面的评论中)。但由于时间都如此接近,所以我采用哪种方法可能并不重要。我想我会使用该VARRAY MEMBER OF方法,因为我可以用一行代码(批量收集)加载数组,而不必循环游标来构建字符串(感谢 @Wernfried 引起MEMBER OF我的注意)...

逗号分隔的列表,例如:,GroupA,GroupB,GroupC,...大约 200 个组...(通过循环光标制作的列表)

FOR i IN 1 .. 10000000 loop
    if myGroups like '%,NONE,%' then
        z:=z+1;
    end if;
end loop;
--690msec
Run Code Online (Sandbox Code Playgroud)

相同的逗号分隔列表(通过循环游标制作的列表)...

FOR i IN 1 .. 10000000 loop
    if instr(myGroups, ',NONE,') > 0 then   
        z:=z+1;
    end if;
end loop;
--818msec
Run Code Online (Sandbox Code Playgroud)

varray,相同的 200 组(由批量收集制作的 varray)...

FOR i IN 1 .. 10000000 loop
    IF 'NONE' MEMBER of myGroups THEN
        z:=z+1;
    end if;
end loop;
--780msec
Run Code Online (Sandbox Code Playgroud)

@Yaroslav Shabalin 建议的关联数组方法(通过循环游标制作的关联数组)...

FOR i IN 1 .. 10000000 loop
    if (a_values('NONE') = 1) then
        z:=z+1;
    end if;
end loop;
--851msec
Run Code Online (Sandbox Code Playgroud)

Bri*_*ity 5

myGroup 是一个 varray 吗?如果是字符串,请尝试以下操作:

select 1
  from dual
 where 'abc,NONE,def' like '%,NONE,%'
Run Code Online (Sandbox Code Playgroud)

很难遵循您正在工作的约束......如果可能的话,在 sql 中执行所有操作,它会更快。

更新:

因此,如果您已经在 plsql 单元中并想留在 plsql 单元中,那么上面的逻辑将是这样的:

declare
    gp varchar2(200) := 'abc,def,NONE,higlmn,op';
  begin
    if ','||gp||',' like '%,NONE,%' then
      dbms_output.put_line('y');
    else
      dbms_output.put_line('n');
    end if;
  end;
Run Code Online (Sandbox Code Playgroud)

如果这本身处于循环中,则将列表设为:

declare
    gp varchar2(200)  := 'abc,def,NONE,higlmn,op';
    gp2 varchar2(200) := ',' || gp || ',';
  begin
    if g2 like '%,NONE,%' then
      dbms_output.put_line('y');
    else
      dbms_output.put_line('n');
    end if;
  end;
Run Code Online (Sandbox Code Playgroud)

也尝试 instr 这可能比这样更快:

  declare
    gp varchar2(200) := ',abc,def,NONE,hig,';
  begin
    if instr(gp, ',NONE,') > 0 then
      dbms_output.put_line('y');
    else
      dbms_output.put_line('n');
    end if;
  end;
Run Code Online (Sandbox Code Playgroud)

我不知道这是否比提到的其他解决方案更快(它很有可能),这是其他尝试。