Oracle에서 지정된 행을 삭제하는 최적의 방법
저는 다양한 크기의 6개 테이블 중 하나에서 수만 개의 행을 삭제해야 하지만 그 사이에 약 3천만 개의 행이 있는 프로젝트가 있습니다.제가 받은 데이터의 구조 때문에, 저는 6개의 테이블 중 어떤 테이블에 삭제해야 할 행이 있는지 모르기 때문에 모든 테이블에 대해 모든 삭제를 실행해야 합니다.ID 열에 대한 인덱스를 작성하여 속도를 높이려고 했지만 속도가 빨라지면 제거할 수 있습니다.
문제는 실제로 삭제를 수행할 수 있는 효율적인 방법을 찾을 수 없다는 것입니다.테스트를 위해 약 9400개의 행이 있는 단일 테스트 테이블에 대해 7384개의 행 삭제를 실행하고 있습니다.Oracle SQL Developer에서 가능한 여러 쿼리 솔루션을 테스트했습니다.
7384 별도DELETE문에 203초가 걸렸습니다.
delete from TABLE1 where ID=1000001356443294;
delete from TABLE1 where ID=1000001356443296;
etc...
7384 별도SELECT문이 57초 소요됨:
select ID from TABLE1 where ID=1000001356443294
select ID from TABLE1 where ID=1000001356443296
etc...
7384 별도DELETE from (SELECT)214초가 걸렸습니다.
delete from (select ID from TABLE1 where ID=1000001356443294);
delete from (select ID from TABLE1 where ID=1000001356443296);
etc...
1 SELECT7384를 포함하는 진술OR의 절은 127.4초를 사용했습니다.
select ID from TABLE1 where ID=1000001356443294 or ID = 1000001356443296 or ...
1 DELETE from (SELECT)7384를 포함하는 진술OR의 절은 74.4초를 사용했습니다.
delete from (select ID from TABLE1 where ID=1000001356443294 or ID = 1000001356443296 or ...)
마지막이 가장 빠를 수도 있지만, 추가 테스트를 통해 9000 행 테이블에서 200,000 행 테이블(최종 테이블 세트 크기의 1% 미만)로 확장할 때에도 동일한 문을 실행하는 데 14분이 소요됩니다.행당 50% 이상 빨라지지만 전체 데이터 세트에 대해 실행될 때는 하루 정도까지 추정됩니다.저는 우리가 이 일을 하는 데 사용했던 소프트웨어가 약 20분 안에 그것을 할 수 있다는 것을 잘 알고 있습니다.
그래서 제 질문은 다음과 같습니다.
- 삭제하는 더 좋은 방법이 있습니까?
- 제가 한 번 사용해볼까요?
SELECT주어진 행이 어떤 테이블에 있는지 검색하고 삭제 쿼리를 실행하는 문(예: 두 번째 테스트)?그마저도 꽤 느려 보이지만...- 삭제 속도를 높이기 위해 제가 할 수 있는 다른 방법이 있나요?DBA 수준의 액세스 권한이나 지식이 없습니다.
질문에 답변하기 전에 다음과 같이 진행하겠습니다.
명령문의 수와 명령문이 발행하는 작업을 상대적으로 최소화합니다.
모든 시나리오에서는 ID 테이블이 있다고 가정합니다.PURGE_IDS합니다.TABLE_1,TABLE_2 타기.
대량 삭제의 경우 CREATE TABLE을 SELECT로 사용하는 것을 고려합니다.
작업이행 중을 삭제하는 삭제하지 마십시오. 30%를 합니다.create table as select유지할 행과 새 테이블을 이전 테이블로 바꿉니다.INSERT /*+ APPEND */ ... NOLOGGING만약 당신이 그것을 살 수 있다면 놀랍도록 저렴합니다.일부 동시 활동이 있더라도 온라인 테이블 재정의를 사용하여 테이블을 제자리에 재구성할 수 있습니다.
행을 삭제하지 않을 것이라는 것을 알고 있는 DELETE 문을 실행하지 않음
ID 값이 여섯 개 테이블 중 하나에 있을 경우 삭제한 ID를 추적하고 다른 테이블에서 해당 ID를 삭제하지 마십시오.
CREATE TABLE TABLE1_PURGE NOLOGGING
AS
SELECT ID FROM PURGE_IDS INNER JOIN TABLE_1 ON PURGE_IDS.ID = TABLE_1.ID;
DELETE FROM TABLE1 WHERE ID IN (SELECT ID FROM TABLE1_PURGE);
DELETE FROM PURGE_IDS WHERE ID IN (SELECT ID FROM TABLE1_PURGE);
DROP TABLE TABLE1_PURGE;
반복합니다.
필요한 경우 동시성 관리
또 다른 방법은 테이블 위에 PL/SQL 루프를 사용하여 행 수 제한 삭제 문을 실행하는 것입니다.이 방법은 삭제를 실행하는 테이블에 대해 삽입/업데이트/삭제 동시 로드가 많은 경우에 가장 적합합니다.
declare
l_sql varchar2(4000);
begin
for i in (select table_name from all_tables
where table_name in ('TABLE_1', 'TABLE_2', ...)
order by table_name);
loop
l_sql := 'delete from ' || i.table_name ||
' where id in (select id from purge_ids) ' ||
' and rownum <= 1000000';
loop
commit;
execute immediate l_sql;
exit when sql%rowcount <> 1000000; -- if we delete less than 1,000,000
end loop; -- no more rows need to be deleted!
end loop;
commit;
end;
삭제할 모든 ID를 테이블에 저장합니다.그러면 세 가지 방법이 있습니다.테이블에 있는 모든 ID를 루프한 다음 X 커밋 간격 동안 한 번에 하나의 행을 삭제합니다.X는 100 또는 1000일 수 있습니다.OLTP 환경에서 작동하며 잠금을 제어할 수 있습니다.
Oracle 대량 삭제 사용
상관된 삭제 쿼리를 사용합니다.
일반적으로 단일 쿼리는 컨텍스트 전환 및 구문 분석이 적기 때문에 여러 쿼리보다 빠릅니다.
먼저 삭제 중에 인덱스를 비활성화하는 것이 좋습니다.
을 사용해 보십시오. MERGE INTO는 다음과 같습니다.
ID와 TABLE1의 추가 열을 가진 임시 테이블을 만들고 다음을 사용하여 테스트합니다.
MERGE INTO table1 src
USING (SELECT id,col1
FROM test_merge_delete) tgt
ON (src.id = tgt.id)
WHEN MATCHED THEN
UPDATE
SET src.col1 = tgt.col1
DELETE
WHERE src.id = tgt.id
저는 이 코드를 시도해 보았는데 제 경우에는 잘 작동합니다.
DELETE FROM NG_USR_0_CLIENT_GRID_NEW WHERE rowid IN
( SELECT rowid FROM
(
SELECT wi_name, relationship, ROW_NUMBER() OVER (ORDER BY rowid DESC) RN
FROM NG_USR_0_CLIENT_GRID_NEW
WHERE wi_name = 'NB-0000001385-Process'
)
WHERE RN=2
);
언급URL : https://stackoverflow.com/questions/10092407/optimal-way-to-delete-specified-rows-from-oracle
'programing' 카테고리의 다른 글
| 셸 스크립트에서 mariadb 암호의 특수 문자를 이스케이프하는 방법 (0) | 2023.07.22 |
|---|---|
| 스크립트에 --verbose 또는 -v 옵션을 구현하는 방법은 무엇입니까? (0) | 2023.07.22 |
| 아이폰을 C++로 프로그래밍할 수 있습니까? (0) | 2023.07.17 |
| numpy, scipy, matplotlib 및 pylab 간의 혼동 (0) | 2023.07.17 |
| 메모리에 이미지를 로드하지 않고 이미지 크기 가져오기 (0) | 2023.07.17 |