강제 Oracle 강제 삭제 글로벌 온도 테이블
이 프로젝트에서 저는 다음과 같은 글로벌 템플릿을 만듭니다.
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
어떤 절차에서는 이 표를 사용해야 하지만 다른 보고서에 따라 변경될 수 있습니다.그래서 항상 테이블을 놓은 다음 필요한 필드로 테이블을 다시 만들어야 합니다.
업무상의 이유로 사용해야 하기 때문에 테이블 등을 사용할 수 없습니다.저는 임시 테이블만 사용할 수 있습니다.행 삭제를 커밋하려고 했지만 이 테이블의 데이터를 사용하기 위해 절차를 호출하면 테이블에 더 이상 행이 없고 해당 행이 삭제되었습니다.
어떤 도움이라도 주시면 대단히 감사하겠습니다, 미리 감사드립니다.
편집
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 글로벌 임시 테이블은 일시적인 개체가 아닙니다.적절한 힙 테이블입니다.한 번만 생성하면 모든 세션에서 해당 세션에서만 볼 수 있는 데이터를 저장하는 데 사용할 수 있습니다.
일시적인 측면은 데이터가 한 번의 트랜잭션 또는 한 세션 이상 지속되지 않는다는 것입니다.주요 구현 세부 정보는 데이터가 영구 테이블스페이스가 아닌 임시 테이블스페이스에 기록된다는 것입니다.그러나 데이터는 여전히 디스크에 쓰고 디스크에서 읽기 때문에 글로벌 임시 테이블을 사용하는 데 상당한 오버헤드가 발생합니다.
요점은 우리가 임시 테이블을 삭제하고 다시 만들면 안 된다는 것입니다.SQL Server 스타일 로직을 Oracle로 포팅하려는 경우 PL/SQL 컬렉션을 사용하여 임시 데이터를 메모리 내에 유지하는 것을 고려해야 합니다.자세히 알아보세요.
의구인원의 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을 작성하는 방법을 배웁니다.종종 우리는 더 나은 액세스 경로로 저장될 수 있는 잘못 작성된 쿼리에 대한 해결책으로 임시 테이블을 사용합니다.
당신의 전체 코드를 보니, 흐름이 훨씬 더 이상해 보입니다.
- 글로벌 임시 테이블 삭제 및 다시 만들기
- 임시 테이블 채우기
- 임시 테이블에서 PL/SQL 배열로 선택
- PL/SQL 배열에서 대량 삽입을 사용하여 실제 테이블에 삽입
여기는 너무 많은 비용과 낭비되는 활동이 있습니다.당신이 해야 할 일은 당신이 삽입한 데이터를 가져오는 것입니다.v2d_temp
으로 직접 수있다니습할력입.vertical_design
에 삽입... 문을 사용하여 *를 선택하는 것이 이상적입니다.PL할 수 .JSON 파일은 Java 파일의 PL/SQL 파일입니다.
글로벌 임시 테이블이 귀사의 시나리오에 적합한 솔루션이 아닌 것으로 확신합니다.
"우리의 상사나 다른 사람들은 그들의 방식을 통해 무언가를 계속하기 때문에, 당신은 그것을 바꿀 수 없습니다."
당신이 가지고 있는 것은 프로그래밍 문제가 아니라 보스 문제입니다.결과적으로 StackOverflow에 관한 한 주제에서 벗어납니다.하지만 여기 몇 가지 제안이 있습니다.
중요한 점은 최적화되지 않은 아키텍처에 대한 타협이 아니라는 점입니다. 즉, 귀사의 상사가 제안하는 것은 다중 사용자 환경에서는 분명히 작동하지 않습니다. 따라서 다음과 같은 옵션을 선택할 수 있습니다.
- 은 합니다.
ORA-14452
오류, 생산으로 진행한 다음 모든 것이 끔찍하게 잘못될 때 "하지만 당신이 나에게 하라고 한" 방어를 사용합니다.이것이 가장 약한 플레이입니다. - 글로벌 테이블을 몰래 폐기하고 다중 사용자 시나리오에서 작동할 무언가를 구현합니다.구현을 실패하면 방어 수단이 없기 때문에 위험이 높습니다.
- 상사와 얘기해 보세요.그들에게 당신이 그들과 마주친다고 말하세요.
ORA-14452
오류, 조사를 했다고 가정하면 이러한 방식으로 글로벌 임시 테이블을 사용하는 것에 대한 근본적인 문제가 있는 것처럼 보이지만 분명히 당신은 무언가를 간과했습니다.그런 다음 이전에 구현한 적이 있을 때 이 문제를 어떻게 해결했는지 물어봅니다.이것은 여러 가지 방법으로 갈 수 있습니다. 아마도 그들은 해결책이 있을 것입니다. 아마도 그들은 이것이 글로벌 임시 테이블을 사용하는 잘못된 방법이라는 것을 깨달을 것입니다. 아마도 그들은 여러분에게 길을 잃으라고 말할 것입니다.어느 쪽이든, 이것이 최선의 접근 방식입니다. 여러분은 적절한 수준으로 우려를 제기했습니다.
행운을 빌어요.
킬링 세션은 ORA-14452 오류를 해결하는 유일한 방법입니다.데이터 사전을 사용하여 임시 테이블을 사용하는 다른 세션을 찾고 다음과 같은 문장으로 해당 세션을 종료합니다.alter system kill session 'sid,seriall#,instance_id';
.
이것은 임시 테이블(Doc ID 800506.1)을 떨어뜨리는 동안 ORA-14452를 진단하는 방법에 대한 Oracle 지원 문서에 언급된 "공식" 솔루션입니다.저는 과거에 이 방법을 성공적으로 사용한 적이 있습니다. 약간 다른 이유 때문입니다.킬링 세션은 상승된 권한이 필요하고 까다로울 수 있습니다. 킬링, 대기, 재시도가 여러 번 필요할 수 있습니다.
이 해결책은 많은 이유로 거의 확실히 나쁜 생각입니다.이를 구현하기 전에 이 정보를 활용하여 잘못된 방법이라는 증거를 제시해야 합니다.예를 들어, "Oracle 설명서에 따르면 이 방법은 다음과 같습니다.alter system
위험하고 몇 가지 보안 문제를 제기하는 특권..".
여기서 고려할 가치가 있는 또 다른 접근법은 임시 테이블이 필요한지 다시 생각해보는 것입니다.
다른 RDBMS에서 Oracle로 전환하여 과도하게 사용하는 사람들 사이에서 매우 일반적인 프로그래밍 관행입니다. 공통 테이블 식과 같은 기능을 사용하여 동일한 쿼리의 다른 부분에서 참조할 수 있는 임시 결과 집합을 암시적으로 구현할 수 있다는 것을 이해하지 못하기 때문입니다.다른 시스템에서는 테이블에 데이터를 기록한 다음 테이블에서 선택하는 것이 당연해졌습니다.
행 처리별 PL/SQL 기반 행이 SQL 기반 집합 처리에 비해 거의 모든 면에서 열등하다는 것을 이해하지 못하는 것이 일반적으로 오류를 더 복잡하게 만듭니다.오류가 발생하기 쉽습니다. 그러나 Oracle은 SQL 처리를 위한 매우 강력한 기능을 제공하므로 필요한 경우에도 SQL SELECT 문에 직접 통합할 수 있습니다.
참고로, 20년 동안 보고 및 ETL을 위한 Oracle 코드를 작성하면서 행별 처리를 한 번만 수행하면 되었고 임시 테이블을 사용할 필요가 없었습니다.
다음을 실행하면 실행 중인 모든 세션을 볼 수 있습니다.
SELECT * FROM V$SESSION
세션을 종료하려면 몇 가지 옵션이 있습니다.다음 명령은 연결을 끊기 전에 현재 진행 중인 트랜잭션이 완료될 때까지 기다립니다.
ALTER SYSTEM DISCONNECT SESSION ‘sid,serial#’ POST_TRANSACTION
다음 명령은 kill -9와 동일하지만 O/S 프로세스를 삭제합니다.
ALTER SYSTEM DISCONNECT SESSION ‘sid,serial#’ IMMEDIATE
후자가 임시 테이블을 제거하지 못하도록 하는 세션을 종료하는 데 가장 효율적입니다.그러나 상당히 무차별적인 힘의 기능이므로 주의하여 사용하십시오.세션이 종료되면 오류가 발생하지 않고 임시 테이블을 제거할 수 있습니다.
세션을 종료하는 다양한 방법에 대한 자세한 내용은 여기에서 확인할 수 있습니다(저는 이 웹 사이트에 소속되어 있지 않습니다. 귀하와 유사한 문제가 있을 때 직접 발견했습니다). https://chandlerdba.wordpress.com/2013/07/25/killing-a-session-dead/
언급URL : https://stackoverflow.com/questions/32423397/force-oracle-drop-global-temp-table
'sourcecode' 카테고리의 다른 글
R을 사용하여 excel-color 정보 읽기 (0) | 2023.06.22 |
---|---|
기본 재배치를 수행한 후 동일한 분기에서 Git 커밋이 중복됩니다. (0) | 2023.06.22 |
PHP-FPM, MariaDB 및 Symfony Form Doctrine 쿼리 작성기의 매우 이상한 동작(오류 503) (0) | 2023.06.17 |
ResolveUrl과 ResolveClientUrl의 차이점은 무엇입니까? (0) | 2023.06.17 |
단일 플라스크 프로세스가 수신하는 동시 요청 수는 얼마나 됩니까? (0) | 2023.06.17 |