3

在为 Oracle 11.2.0.1.0 开发域索引期间(问题也出现在 12 中)我面临着 在使用 ARRAY DML选项创建索引类型的情况下 对函数ODCIIndexInsert的参数类型的误解

根据 Oracle 文档 http://docs.oracle.com/cd/E11882_01/appdev.112/e10765/ext_idx_ref.htm#i76892

在 WITH ARRAY DML 选项的情况下,Oracle 将调用具有以下签名的 ODCIIndexInsert

FUNCTION ODCIIndexInsert(
  ia ODCIIndexInfo,
  ridlist ODCIRidList,
  newvallist varray_of_column_type,
  env ODCIEnv)
RETURN NUMBER

在我的情况下,索引列的数据类型为 NUMBER,所以我将varray_of_column_type定义为SYS.ODCINumberList

STATIC FUNCTION ODCIIndexInsert(ia in sys.ODCIIndexInfo, ridlist in sys.ODCIRidList,  newvallist in sys.ODCINumberList, env in SYS.ODCIEnv) RETURN NUMBER

Indextype 被创建为

CREATE INDEXTYPE test_index_type
FOR
test_eq(number, number)
USING index_methods
WITH ARRAY DML(number, sys.ODCINumberList)
WITH LOCAL RANGE PARTITION
WITH SYSTEM MANAGED STORAGE TABLES;

或者

CREATE INDEXTYPE test_index_type
FOR
test_eq(number, number)
USING index_methods
WITH ARRAY DML
WITH LOCAL RANGE PARTITION
WITH SYSTEM MANAGED STORAGE TABLES;

(在所有情况下都会出现问题)

CREATE TABLE test_table (id NUMBER (19,0));
CREATE INDEX test_index ON test_table(id) INDEXTYPE IS test_index_type;

尝试在表中插入数据时

insert into test_table values (1);

oracle引发异常

Error starting at line 53 in command:
insert into test_table values (1)
Error at Command Line:53 Column:1
Error report:
SQL Error: ORA-29925: cannot execute SCOTT.INDEX_METHODS.ODCIINDEXINSERT
ORA-06553: PLS-306: wrong number or types of arguments in call to 'ODCIINDEXINSERT'
ORA-06553: PLS-306: wrong number or types of arguments in call to 'ODCIINDEXINSERT'
29925. 00000 -  "cannot execute %s"
*Cause:    The specified function does not exist or does not have an
           appropriate signature.
*Action:   Implement the function with the appropriate signature.

所以我的问题是。它是 oracle 的正常行为(根据文档)吗?在使用“WITH ARRAY DML”选项创建 INDEXTYPE并且索引列具有NUMBER数据类型的事实的情况下, ODCIIndexInsert 函数的正确签名是什么?

顺便说一句,如果我定义 没有“WITH ARRAY DML”选项签名的索引类型是明确的,并且可以正常工作。但是这种方法并不能满足我们的性能需求。

此外,如果我使用选项“WITH ARRAY DML WITHOUT COLUMN DATA”定义索引类型并使用签名

static function ODCIIndexInsert(ia sys.odciindexinfo,   ridlist sys.odciridlist, env sys.ODCIEnv) return number

一切正常。但是这种方法并不能满足我们的业务需求。

是否可以定义 ODCIIndexInsert 参数类型(在索引编号列的情况下)以便根据文档进行批量插入?

FUNCTION ODCIIndexInsert(
      ia ODCIIndexInfo,
      ridlist ODCIRidList,
      newvallist varray_of_column_type,
      env ODCIEnv)

我正在附加完整的 sql 脚本来重新创建环境并重现问题。

类型定义:

CREATE OR REPLACE TYPE index_methods AS OBJECT
(
  step number,
  STATIC FUNCTION ODCIGetInterfaces(ifclist OUT SYS.ODCIObjectList) RETURN NUMBER,
  STATIC FUNCTION ODCIIndexCreate (ia SYS.ODCIIndexInfo, parms VARCHAR2, env SYS.ODCIEnv) RETURN NUMBER,
  STATIC FUNCTION ODCIIndexAlter (ia sys.ODCIIndexInfo, parms IN OUT VARCHAR2, altopt number, env sys.ODCIEnv) RETURN NUMBER,
  STATIC FUNCTION ODCIIndexDrop(ia SYS.ODCIIndexInfo, env SYS.ODCIEnv) RETURN NUMBER,
  STATIC FUNCTION ODCIIndexExchangePartition(ia SYS.ODCIIndexInfo, ia1 SYS.ODCIIndexInfo, env SYS.ODCIEnv) RETURN NUMBER,
  STATIC FUNCTION ODCIIndexUpdPartMetadata(ia sys.ODCIIndexInfo, palist sys.ODCIPartInfoList, env sys.ODCIEnv) RETURN NUMBER,
  STATIC FUNCTION ODCIIndexInsert(ia in sys.ODCIIndexInfo, ridlist in sys.ODCIRidList,  newvallist in sys.ODCINumberList, env in SYS.ODCIEnv) RETURN NUMBER,
  STATIC FUNCTION ODCIIndexDelete(ia SYS.ODCIIndexInfo, rid VARCHAR2, oldval number, env SYS.ODCIEnv) RETURN NUMBER,
  STATIC FUNCTION ODCIIndexUpdate(ia SYS.ODCIIndexInfo, rid VARCHAR2, oldval number, newval number, env SYS.ODCIEnv) RETURN NUMBER,
  STATIC FUNCTION ODCIIndexStart(sctx IN OUT index_methods, ia SYS.ODCIIndexInfo,
    op SYS.ODCIPredInfo, qi sys.ODCIQueryInfo, strt number, stop number, cmpval number, env SYS.ODCIEnv) RETURN NUMBER,
  MEMBER FUNCTION ODCIIndexFetch(self IN OUT index_methods, nrows NUMBER, rids OUT SYS.ODCIridlist, env SYS.ODCIEnv) RETURN NUMBER,
  MEMBER FUNCTION ODCIIndexClose(self IN index_methods, env SYS.ODCIEnv) RETURN NUMBER
);

CREATE OR REPLACE TYPE BODY index_methods IS

STATIC FUNCTION ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) RETURN NUMBER IS
BEGIN
  ifclist := sys.ODCIObjectList(sys.ODCIObject('SYS','ODCIINDEX2'));
  RETURN ODCIConst.Success;
END ODCIGetInterfaces;

STATIC FUNCTION ODCIIndexCreate (ia sys.ODCIIndexInfo, parms VARCHAR2,  env sys.ODCIEnv) RETURN NUMBER IS
BEGIN
  RETURN ODCIConst.Success;
END ODCIIndexCreate;

STATIC FUNCTION ODCIIndexDrop(ia sys.ODCIIndexInfo, env sys.ODCIEnv) RETURN NUMBER IS
BEGIN
  RETURN ODCIConst.Success;
END ODCIIndexDrop;

STATIC FUNCTION ODCIIndexAlter (
  ia sys.ODCIIndexInfo,
  parms IN OUT VARCHAR2,
  altopt NUMBER,
  env sys.ODCIEnv)
RETURN NUMBER IS
BEGIN
  RETURN ODCIConst.Success;
END ODCIIndexAlter;

STATIC FUNCTION ODCIIndexUpdPartMetadata(
  ia sys.ODCIIndexInfo,
  palist sys.ODCIPartInfoList,
  env sys.ODCIEnv)
RETURN NUMBER IS
BEGIN
  RETURN ODCIConst.Success;
END ODCIIndexUpdPartMetadata;


STATIC FUNCTION ODCIIndexExchangePartition(
  ia sys.ODCIIndexInfo,
  ia1 sys.ODCIIndexInfo,
  env sys.ODCIEnv)
RETURN NUMBER IS 
BEGIN
  RETURN ODCIConst.Success;
END ODCIIndexExchangePartition;



STATIC FUNCTION ODCIIndexInsert(
   ia sys.ODCIIndexInfo,
   ridlist sys.ODCIRidList,
   newvallist sys.ODCINumberList,
   env sys.ODCIEnv)
RETURN NUMBER IS
BEGIN 
  return ODCIConst.Success;
END;

STATIC FUNCTION ODCIIndexDelete(
   ia SYS.ODCIIndexInfo,
   rid VARCHAR2,
   oldval number,
   env SYS.ODCIEnv)
RETURN NUMBER IS
BEGIN
  return ODCIConst.Success;
END;


STATIC FUNCTION ODCIIndexUpdate(
   ia SYS.ODCIIndexInfo,
   rid VARCHAR2,
   oldval number,
   newval number,
   env SYS.ODCIEnv)
RETURN NUMBER AS
BEGIN
  return ODCIConst.Success;
END;


STATIC FUNCTION ODCIIndexStart(
  sctx IN OUT index_methods,
  ia SYS.ODCIIndexInfo,
  op SYS.ODCIPredInfo,
  qi sys.ODCIQueryInfo,
  strt number,
  stop number,
  cmpval  number,
  env SYS.ODCIEnv)
RETURN NUMBER AS 
BEGIN
  sctx := index_methods(1);
  return ODCIConst.Success;
END;


MEMBER FUNCTION ODCIIndexFetch(
  self IN OUT index_methods,
  nrows NUMBER,
  rids OUT SYS.ODCIridlist,
  env SYS.ODCIEnv)
RETURN NUMBER AS
BEGIN
  return ODCIConst.Success;
END;


MEMBER FUNCTION ODCIIndexClose(self IN index_methods, env SYS.ODCIEnv) RETURN NUMBER AS
BEGIN
  return ODCIConst.Success;
END;

end;

问题解决方法:

--drop function test_eq_fun;

CREATE FUNCTION test_eq_fun(a number, b number) RETURN NUMBER AS
BEGIN
  IF a = b then
    RETURN 1;
  ELSE
    RETURN 0;
  END IF;
END;

--drop operator test_eq;
CREATE OPERATOR test_eq
BINDING (number, number) RETURN NUMBER
USING test_eq_fun;


--drop indextype test_index_type;
CREATE INDEXTYPE test_index_type
FOR
test_eq(number, number)
USING index_methods
WITH ARRAY DML(number, sys.ODCINumberList)
WITH LOCAL RANGE PARTITION
WITH SYSTEM MANAGED STORAGE TABLES;

/*
CREATE INDEXTYPE test_index_type
FOR
test_eq(number, number)
USING index_methods
WITH ARRAY DML
WITH LOCAL RANGE PARTITION
WITH SYSTEM MANAGED STORAGE TABLES;
*/


--drop table test_table;
CREATE TABLE test_table (id NUMBER (19,0));

CREATE INDEX test_index ON test_table(id) INDEXTYPE IS test_index_type;


insert into test_table values (1);
4

2 回答 2

1

我在 https://forums.oracle.com/thread/2582903上得到了正确答案,所以我交叉发布研究以填补知识库。

如果您想使用“WITH ARRAY DML”选项。您必须同时实现单行版本的插入方法和多行版本的插入方法。

当您插入单行时,oracle 总是调用单行版本的方法。

但是,当您在其中插入多行时,oracle 会调用单行和多行方法的组合。

如果您的表没有分区,那么 oracle 调用多行版本是您要插入两个或更多记录。

如果表已分区,则将为插入数据的每个部分调用 ODCIIndexInsert。因此,如果您在 5 个分区中插入 5 行(每个分区 1 行),Oracle 将调用单个方法 5 次。但是,如果您在分区中插入两行或多行,oracle 将为该分区调用多行版本的方法。

希望这会有所帮助。

于 2013-09-18T09:03:02.387 回答
0

另请注意 1) 即使 WITH ARRAY DML 选项也不能保证 Oracle 在一次调用 ODCIIndexInsert 时插入所有行。我已经看到了 Oracle 将多次调用 ARRAY DML 版本的 ODCIIndexInsert 以插入所有行的示例。在我的示例中,Oracle 每次都在 200 到 53 行之间不断更改 nrows。我假设这取决于 SGA 内存大小、缓冲区设置和要插入的行的大小。如果您知道如何避免这种情况,我想知道

2) ODCIIndexDelete 没有类似的 WITH ARRAY DML 选项。这显着减慢了 DELETE 的速度,因为它必须一次完成 1 行。有趣的是,Oracle 文本盒对象 TextIndexMethods 使用数组 dml 的接口(ridlist ODCINUMBERLIST)定义了 ODCIIndexDelete。

于 2013-09-23T15:10:28.837 回答