【发布时间】:2011-07-08 08:02:46
【问题描述】:
是否可以通过 JDBC 在 Oracle 中直接加载 INSERT?
我目前使用批处理的预处理语句(通过 Spring JDBC),有什么方法可以绕过 NOLOGGING 表上的重做日志?
这适用于 Oracle 11g。
【问题讨论】:
是否可以通过 JDBC 在 Oracle 中直接加载 INSERT?
我目前使用批处理的预处理语句(通过 Spring JDBC),有什么方法可以绕过 NOLOGGING 表上的重做日志?
这适用于 Oracle 11g。
【问题讨论】:
直接路径插入只能在insert into x as select * from y 场景中进行。这可以使用jdbc来完成,没问题。这不能通过插入和值来完成。当数据库处于强制记录模式时,这也无法完成。大多数情况下,当备用数据库处于连接状态时,主数据库将处于强制记录模式。
正如 Gary Myers 所提到的,从 11gR2 开始就有 APPEND_VALUES 提示。与“旧”附加提示一样,它只能用于批量插入。
我希望这会有所帮助, 罗纳德。
【讨论】:
在 11gR2 中引入了 APPEND_VALUES 提示,用于使用 INSERT...VALUES 进行直接路径插入。
没有可用的 11gR2 实例来测试它是否适用于 JDBC batch inserts。不过值得一试。
【讨论】:
我能够将 APPEND_VALUES 提示与 Oracle 12c 和 JDBC 批处理一起使用。我通过 Oracle Enterprise manager 验证了直接路径插入,其中解释计划显示 Load As Select
编辑:我不再参与该项目,但我尝试提出更多细节: 代码类似于:
prepareTableForLargeInsert("TABLE_X")
preparedStatement = conn.prepareStatement("INSERT /*+ APPEND_VALUES */ INTO TABLE_X(A, B) VALUES(?,?)");
while(thereIsStuffToInsert()) {
for (ThingToWrite entity : getBatch()) {
int i = 1;
preparedStatement.setLong(i++, entity.getA());
preparedStatement.setString(i++, entity.getB());
...
}
preparedStatement.executeBatch();
preparedStatement.clearParameters();
}
repairTableAfterLargeInsert("TABLE_X")
需要验证是否真的使用了直接路径(表被锁定/在同一个 tx 中的常规插入失败/实际执行计划显示 Load As Select)
方法 prepareTableForLargeInsert 和 repairTableAfterLargeInsert 正在调用存储过程。它们可能会有所帮助:
PROCEDURE sp_before_large_insert (in_table_name IN VARCHAR2) AS
BEGIN
-- force parallel processing
EXECUTE IMMEDIATE 'ALTER SESSION FORCE PARALLEL DML';
EXECUTE IMMEDIATE 'ALTER SESSION FORCE PARALLEL QUERY';
EXECUTE IMMEDIATE 'ALTER SESSION FORCE PARALLEL DDL';
-- set table to NOLOGGING
EXECUTE IMMEDIATE 'ALTER TABLE ' || in_table_name || ' NOLOGGING';
-- disable all FK constraints referencing the table. all but those used for Partition by reference
FOR cur IN (SELECT a.owner, a.constraint_name, a.table_name
FROM all_cons_columns a
JOIN all_constraints c ON a.owner = c.owner
AND a.constraint_name = c.constraint_name
JOIN all_constraints c_pk ON c.r_owner = c_pk.owner
AND C.R_CONSTRAINT_NAME = C_PK.CONSTRAINT_NAME
LEFT JOIN user_part_tables pt on pt.ref_ptn_constraint_name = c.constraint_name
WHERE C.CONSTRAINT_TYPE = 'R'
AND pt.ref_ptn_constraint_name IS NULL
AND A.OWNER LIKE '%_OWNER'
AND c_pk.table_name = in_table_name)
LOOP
execute immediate 'ALTER TABLE "'||cur.owner||'"."'||cur.table_name||'" MODIFY CONSTRAINT "'||cur.constraint_name||'" DISABLE';
END LOOP;
-- disable FKs (but one used for Partition by reference), PK (unless referenced by enabled FK for partition reference) and UCs on table
FOR c IN (select distinct rc.CONSTRAINT_NAME FROM user_constraints rc
LEFT JOIN user_part_tables pt on pt.ref_ptn_constraint_name = rc.constraint_name
LEFT JOIN user_constraints c_fk ON c_fk.R_CONSTRAINT_NAME = rc.CONSTRAINT_NAME AND c_fk.status = 'ENABLED'
WHERE rc.owner like '%OWNER'
AND pt.ref_ptn_constraint_name IS NULL
AND c_fk.R_CONSTRAINT_NAME IS NULL
AND rc.CONSTRAINT_TYPE IN ('R', 'U', 'P')
AND rc.TABLE_NAME = in_table_name)
LOOP
EXECUTE IMMEDIATE 'ALTER TABLE ' || in_table_name || ' DISABLE CONSTRAINT ' || c.CONSTRAINT_NAME;
END LOOP;
-- set unusable non-local non-unique indexes on table
FOR c IN (select INDEX_NAME from all_indexes
where table_owner LIKE '%_OWNER'
and PARTITIONED = 'NO'
and UNIQUENESS = 'NONUNIQUE'
and STATUS = 'VALID'
and TABLE_NAME = in_table_name)
LOOP
EXECUTE IMMEDIATE 'ALTER INDEX ' || c.index_name || ' UNUSABLE';
END LOOP;
END sp_before_large_insert;
PROCEDURE sp_after_large_insert (in_table_name IN VARCHAR2) AS
BEGIN
-- rebuild disabled indexes on table
FOR c IN (select INDEX_NAME from all_indexes
where table_owner LIKE '%_OWNER'
and STATUS = 'UNUSABLE'
and TABLE_NAME = in_table_name)
LOOP
EXECUTE IMMEDIATE 'ALTER INDEX ' || c.index_name || ' REBUILD PARALLEL NOLOGGING';
END LOOP;
-- enable FKs, PK and UCs on table
FOR c IN (select CONSTRAINT_NAME, CONSTRAINT_TYPE
FROM user_constraints
WHERE owner like '%OWNER'
AND CONSTRAINT_TYPE IN ('R', 'U', 'P')
AND TABLE_NAME = in_table_name)
LOOP
IF c.CONSTRAINT_TYPE = 'P' THEN
EXECUTE IMMEDIATE 'ALTER TABLE ' || in_table_name || ' ENABLE CONSTRAINT ' || c.CONSTRAINT_NAME || ' USING INDEX REVERSE';
ELSE
EXECUTE IMMEDIATE 'ALTER TABLE ' || in_table_name || ' ENABLE CONSTRAINT ' || c.CONSTRAINT_NAME;
END IF;
END LOOP;
-- enable FKs constraints on related tables
FOR cur IN (select fk.owner, fk.constraint_name , fk.table_name
from all_constraints fk, all_constraints pk
where fk.CONSTRAINT_TYPE = 'R' and
pk.owner LIKE '%_OWNER' and
fk.r_owner = pk.owner and
fk.R_CONSTRAINT_NAME = pk.CONSTRAINT_NAME and
pk.TABLE_NAME = in_table_name)
LOOP
execute immediate 'ALTER TABLE "'||cur.owner||'"."'||cur.table_name||'" MODIFY CONSTRAINT "'||cur.constraint_name||'" ENABLE';
END LOOP;
-- set table to LOGGING
EXECUTE IMMEDIATE 'ALTER TABLE ' || in_table_name || ' LOGGING';
-- disable parallel processing
EXECUTE IMMEDIATE 'ALTER SESSION DISABLE PARALLEL DML';
EXECUTE IMMEDIATE 'ALTER SESSION DISABLE PARALLEL QUERY';
EXECUTE IMMEDIATE 'ALTER SESSION DISABLE PARALLEL DDL';
-- clean up indexes i.e. set logging and noparallel again
FOR c IN (SELECT INDEX_NAME FROM ALL_INDEXES
WHERE (TRIM(DEGREE) > TO_CHAR(1) OR LOGGING = 'NO')
AND OWNER LIKE '%_OWNER'
AND TABLE_NAME = in_table_name)
LOOP
EXECUTE IMMEDIATE 'ALTER INDEX ' || c.index_name || ' NOPARALLEL LOGGING';
END LOOP;
END sp_after_large_insert;
我记得为禁用的 UC 重新创建定制索引时存在问题,例如因为丢失了它们是如何分区的信息(全局哈希分区)(使索引只是 UNUSABLE 不起作用)
注意事项:
【讨论】:
有
insert /*+ append */ into desttab select * from srctab
不能在 JDBC 中工作?
【讨论】:
用途:
INSERT /*+ APPEND_VALUES */ INTO table_name (column1, column2) values (?,?);
【讨论】: