0

我有一个应该用多列搜索的表,它可以有多个值

create table t as select * from all_objects;

create bitmap index IDX_DATA_OBJECT_ID on T (DATA_OBJECT_ID);
create bitmap index IDX_LAST_DDL_TIME on T (LAST_DDL_TIME);
create bitmap index IDX_OBJECT_NAME on T (OBJECT_NAME);
create bitmap index IDX_OBJECT_TYPE on T (OBJECT_TYPE);

create or replace type strarray as table of varchar2(4000)

CREATE OR REPLACE PROCEDURE p_search(op_cursor out SYS_REFCURSOR
                                ,a         strarray
                                ,b         strarray) IS
                                ca constant number:= a.count;
                                cb constant number:= b.count;
BEGIN
  OPEN op_cursor FOR
  SELECT /*+ gather_plan_statistics asda*/  *
    FROM t
   WHERE object_name IN (SELECT * FROM TABLE(a))
     AND object_type IN (SELECT * FROM TABLE(b));
END;

declare
  op_cursor sys_refcursor;
  c t%rowtype;
begin
  p_search(op_cursor,strarray('ICOL$'),strarray('TABLE'));
  loop
    fetch op_cursor into c;
    exit when op_cursor%notfound;
  end loop;
end;

-----------------------------------------------------------------
| Id  | Operation                             | Name            |
-----------------------------------------------------------------
|   0 | SELECT STATEMENT                      |                 |
|*  1 |  HASH JOIN SEMI                       |                 |
|   2 |   NESTED LOOPS                        |                 |
|   3 |    NESTED LOOPS                       |                 |
|   4 |     SORT UNIQUE                       |                 |
|   5 |      COLLECTION ITERATOR PICKLER FETCH|                 |
|   6 |     BITMAP CONVERSION TO ROWIDS       |                 |
|*  7 |      BITMAP INDEX SINGLE VALUE        | IDX_OBJECT_NAME |
|   8 |    TABLE ACCESS BY INDEX ROWID        | T               |
|   9 |   COLLECTION ITERATOR PICKLER FETCH   |                 |
-----------------------------------------------------------------

它对我来说看起来不错,因为它在更具选择性的列上进行索引查找。但是如果没有传递参数,我也需要搜索所有值,我真的很坚持。

我认为的主要问题是如何编写 sql 来通过多列搜索表,这些列中有多个可能的值?我希望能够利用位图索引。

我应该坚持使用动态 SQL 来完成这样的任务吗?

更新。这就是我目前解决它的方式。

create context my_ctx using p_search;

CREATE OR REPLACE FUNCTION in_list(p_string IN VARCHAR2) RETURN strarray AS
   l_string LONG DEFAULT p_string || ',';
   l_data   strarray := strarray();
   n        NUMBER;
BEGIN
   LOOP
      EXIT WHEN l_string IS NULL;
      n := instr(l_string, ',');
      l_data.extend;
      l_data(l_data.count) := ltrim(rtrim(substr(l_string, 1, n - 1)));
      l_string := substr(l_string, n + 1);
   END LOOP;

   RETURN l_data;
END;

CREATE OR REPLACE PROCEDURE p_search(op_cursor OUT SYS_REFCURSOR
                                    ,a         VARCHAR2
                                    ,b         VARCHAR2) IS
   l VARCHAR2(4000);
BEGIN
   l := 'SELECT /*+ gather_plan_statistics lvv3*/
       *
        FROM t
       WHERE 1=1';

   IF a IS NOT NULL
   THEN
      dbms_session.set_context('MY_CTX', 'OBJ_NAME', a);
      l := l || ' and t.object_name in (select /*+ cardinality (objn 5)*/ * from table(cast(in_list(sys_context( ''MY_CTX'',''OBJ_NAME'' )) as strarray)
                                             ) objn
                         )';
   END IF;

   IF b IS NOT NULL
   THEN
      dbms_session.set_context('MY_CTX', 'OBJ_TYPE', b);
      l := l || ' and t.object_type in (select /*+ cardinality (objt 5)*/ * from table(cast(in_list(sys_context( ''MY_CTX'',''OBJ_TYPE'' )) as strarray)
                                             ) objt
                         )';
   END IF;

   OPEN op_cursor FOR l;
   dbms_session.clear_context('MY_CTX');
END;
4

0 回答 0