强制Oracle删除全局临时表
在我们的项目中,我创建了一些全局临时表,如下所示:强制Oracle删除全局临时表,oracle,plsql,ddl,temp-tables,Oracle,Plsql,Ddl,Temp Tables,在我们的项目中,我创建了一些全局临时表,如下所示: CREATE GLOBAL TEMPORARY TABLE v2dtemp ( id NUMBER, GOOD_TYPE_GROUP VARCHAR2(250 BYTE), GOOD_CODE VARCHAR2(50 BYTE), GOOD_TITLE VARCHAR2(250 BYTE) ) ON COMMIT PRESERVE ROWS; 但当我
CREATE GLOBAL TEMPORARY TABLE v2dtemp (
id NUMBER,
GOOD_TYPE_GROUP VARCHAR2(250 BYTE),
GOOD_CODE VARCHAR2(50 BYTE),
GOOD_TITLE VARCHAR2(250 BYTE)
)
ON COMMIT PRESERVE ROWS;
但当我想放下这张桌子时,问题就来了。
Oracle不会让我放弃这张表,它说:
ORA-14452: attempt to create, alter or drop an index on temporary table already in use
我必须在某些程序中使用此表,但它可能会根据其他报告进行更改。因此,我应该始终删除表,然后使用所需字段重新创建它
出于某些商业原因,我不得不使用它,所以我不可能使用表或其他东西。我可以只使用临时表。
我尝试了commit delete rows,但当我调用我的过程来使用此表中的数据时,表中没有更多的行,它们已被删除
任何帮助都将不胜感激,
提前谢谢
///编辑
public void saveJSONBatchOpenJobs(final JSONArray array, MtdReport report) {
dropAndCreateTable();
String sql = "INSERT INTO v2d_temp " +
"(ID, KARPARDAZ, GOOD_TYPE_GROUP, GOOD_CODE, GOOD_TITLE, COUNT, "
+ "FACTOR_COUNT, GHABZ_COUNT, DEAL_NO, DEAL_DATE, REQUEST_NO, REQUEST_DATE, "
+ "REQUEST_CLIENT, STATUS, TYPE, MTDREPORT_ID, GEN_SECURITY_DATA_ID) " +
"VALUES (MTD_KARPARDAZ_OPEN_JOBS_SEQ.nextval,?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
getJdbcTemplate().batchUpdate(sql, new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
JSONArray values = array.getJSONArray(i);
if(!values.get(0).equals("null"))
ps.setString(1, values.get(0).toString());
else
ps.setNull(1, Types.VARCHAR);
if(!values.get(1).equals("null"))
ps.setString(2, values.get(1).toString());
else
ps.setNull(2, Types.VARCHAR);
if(!values.get(2).equals("null"))
ps.setString(3, values.get(2).toString());
else
ps.setNull(3, Types.VARCHAR);
if(!values.get(3).equals("null"))
ps.setString(4, values.get(3).toString());
else
ps.setNull(4, Types.VARCHAR);
if(!values.get(4).equals("null"))
ps.setBigDecimal(5, new BigDecimal(values.get(4).toString()));
else
ps.setNull(5, Types.NUMERIC);
if(!values.get(5).equals("null"))
ps.setBigDecimal(6, new BigDecimal(values.get(5).toString()));
else
ps.setNull(6, Types.NUMERIC);
if(!values.get(6).equals("null"))
ps.setBigDecimal(7, new BigDecimal(values.get(6).toString()));
else
ps.setNull(7, Types.NUMERIC);
if(!values.get(7).equals("null"))
ps.setString(8, values.get(7).toString());
else
ps.setNull(8, Types.VARCHAR);
if(!values.get(8).equals("null"))
ps.setDate(9, new Date(new Timestamp(values.getLong(8)).getDateTime()));
else
ps.setNull(9, Types.DATE);
if(!values.get(9).equals("null"))
ps.setString(10, values.get(9).toString());
else
ps.setNull(10, Types.VARCHAR);
if(!values.get(10).equals("null"))
ps.setDate(11, new Date(new Timestamp(values.getLong(8)).getDateTime()));
else
ps.setNull(11, Types.DATE);
if(!values.get(11).equals("null"))
ps.setString(12, values.get(11).toString());
else
ps.setNull(12, Types.VARCHAR);
if(!values.get(12).equals("null"))
ps.setString(13, values.get(12).toString());
else
ps.setNull(13, Types.VARCHAR);
if(!values.get(13).equals("null"))
ps.setString(14, values.get(13).toString());
else
ps.setNull(14, Types.VARCHAR);
if(!values.get(14).equals("null"))
ps.setLong(15, new Long(values.get(14).toString()));
else
ps.setNull(15, Types.NUMERIC);
if(!values.get(15).equals("null"))
ps.setLong(16, new Long(values.get(15).toString()));
else
ps.setNull(16, Types.NUMERIC);
}
@Override
public int getBatchSize() {
return array.size();
}
});
String bulkInsert = "declare "
+ "type array is table of d2v_temp%rowtype;"
+ "t1 array;"
+ "begin "
+ "select * bulk collect into t1 from d2v_temp;"
+ "forall i in t1.first..t1.last "
+ "insert into vertical_design values t1(i);"
+ "end;";
executeSQL(bulkInsert);
}
private void dropAndCreateTable() {
String dropSql = "declare c int;"
+ "begin "
+ "select count(*) into c from user_tables where table_name = upper('v2d_temp');"
+ "if c = 1 then "
+ "truncate table v2d_temp"
+ "drop table v2d_temp;"
+ " end if;"
+ "end;";
executeSQL(dropSql);
String createSql = "CREATE GLOBAL TEMPORARY TABLE v2d_temp (\n"
+ "DEAL_ID NUMBER,\n"
+ "id NUMBER,\n"
+ "karpardaz VARCHAR2(350),\n"
+ "GOOD_TYPE_GROUP VARCHAR2(250 BYTE),\n"
+ "GOOD_CODE VARCHAR2(50 BYTE),\n"
+ "GOOD_TITLE VARCHAR2(250 BYTE),\n"
+ "COUNT NUMBER,\n"
+ "FACTOR_COUNT NUMBER,\n"
+ "GHABZ_COUNT NUMBER,\n"
+ "DEAL_NO VARCHAR2(50 BYTE),\n"
+ "DEAL_DATE DATE,\n"
+ "REQUEST_NO VARCHAR2(50 BYTE),\n"
+ "REQUEST_DATE DATE,\n"
+ "REQUEST_CLIENT VARCHAR2(250 BYTE),\n"
+ "STATUS VARCHAR2(250 BYTE),\n"
+ "TYPE VARCHAR2(250 BYTE),\n"
+ "GEN_SECURITY_DATA_ID NUMBER(10),\n"
+ "MTDREPORT_ID NUMBER\n"
+ ")\n"
+ "ON COMMIT PRESERVE ROWS";
executeSQL(createSql);
}
private void executeSQL(String sql) {
Connection con = null;
try {
con = getConnection();
Statement st = con.createStatement();
st.execute(sql);
} catch (SQLException e) {
e.printStackTrace();
} finally {
if(con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
Oracle全局临时表不是临时对象。它们是适当的堆表。我们创建它们一次,任何会话都可以使用它们来存储仅对该会话可见的数据 临时方面是数据在一个事务或一个会话之后不会持久化。关键的实现细节是将数据写入临时表空间,而不是永久表空间。但是,数据仍然被写入磁盘或从磁盘读取,因此使用全局临时表会带来显著的开销 关键是我们不应该删除并重新创建临时表。如果您试图将SQLServer样式逻辑移植到Oracle中,则应该考虑使用PL/SQL集合来维护内存中的临时数据。p>
ORA-14452
的具体原因是,如果全局临时表在会话期间包含数据,则无法删除具有会话范围持久性的全局临时表。即使表当前为空
SQL> create global temporary table gtt23 (col1 number)
2 on commit preserve rows
3 /
Table created.
SQL> insert into gtt23 values (1);
1 row created.
SQL> commit;
Commit complete.
SQL> delete from gtt23;
1 row deleted.
SQL> commit;
Commit complete.
SQL> drop table gtt23;
drop table gtt23
*
ERROR at line 1:
ORA-14452: attempt to create, alter or drop an index on temporary table already in use
SQL>
解决方案是结束会话并重新连接,或者(有点奇怪)截断表,然后删除它
SQL> truncate table gtt23;
Table truncated.
SQL> drop table gtt23;
Table dropped.
SQL>
如果其他会话正在使用全局临时表-这是可能的(因此使用全局命名法),那么在所有会话断开连接之前,您将无法删除该表
因此,真正的解决方案是学会正确使用全局临时表:创建特定的全局临时表以匹配每个报表。或者,如我所说,改用PL/SQL集合。或者,甚至只是学习编写经过良好调优的SQL。通常,我们使用临时表作为一种解决方法,以避免编写不好的查询,而这些查询可以通过更好的访问路径保存
查看了完整的代码后,流程看起来更奇怪:
v2d\u temp
中的数据直接填充到vertical\u design
,理想情况下插入到。。。从语句中选择*FROM。将JSON数组转换为查询需要一些预处理,但这在Java或PL/SQL中都很容易实现
在我看来,全局临时表并不是适合您的场景的正确解决方案
“我们的老板或其他人坚持按自己的方式做事,所以你无法改变” 您遇到的是老板问题而不是编程问题。因此,就StackOverflow而言,它是离题的。但这里还是有一些建议 要记住的关键一点是,我们不是在讨论一些次优架构的折衷方案:您的老板提出的方案显然在多用户环境中不起作用。因此,您的选择是:
ORA-14452
错误,继续生产,然后在出现严重错误时使用“但你告诉我要”防御。这是最弱的一出戏ORA-14452
错误,说您已经做了一些调查,以这种方式使用全局临时表似乎是一个基本问题,但显然您忽略了一些东西。然后,问他们以前实现过这个问题,他们是如何解决这个问题的。这可能有多种方式,也许他们有解决办法,也许他们会意识到这是使用全局临时表的错误方式,也许他们会告诉你滚开。无论哪种方式,这都是最好的方法:您已将关注点提升到适当的级别祝你好运。终止会话是解决ORA-14452错误的唯一方法。使用数据字典查找使用临时表的其他会话并杀死它们 使用类似于
alter system kill session'sid,seriall#,instance_id'的语句代码>
这是Oracle支持文档中提到的“官方”解决方案
如何在删除临时表(文档ID 800506.1)期间诊断ORA-14452。我过去曾成功地使用过这种方法,原因稍有不同。
终止会话需要提升权限,而且可能很棘手;它可能需要杀戮、等待,然后重试几次
出于许多原因,这种解决方案几乎肯定是个坏主意。在实现此功能之前,您应该尝试利用此信息来证明这是正确的
这是错误的做法。例如,“Oracle文档说明此方法需要alter system
特权,这是危险的,会引起一些问题
安全问题…。另一个值得考虑的方法是重新考虑是否需要临时表
在那些从其他RDBMS过渡到Oracle而过度使用它们的人中,这是一种非常常见的编程实践,因为他们不理解您可以将这些特性作为通用特性来使用
SELECT * FROM V$SESSION
ALTER SYSTEM DISCONNECT SESSION ‘sid,serial#’ POST_TRANSACTION
ALTER SYSTEM DISCONNECT SESSION ‘sid,serial#’ IMMEDIATE