30,000,000 개의 행 테이블에서 DELETE 명령이 완료되지 않음


22

데이터베이스를 상속했으며 정리하고 속도를 높이려고합니다. 30,000,000 개의 행을 포함하는 테이블이 있는데 그 중 많은 수는 프로그래머를 대신하여 오류로 인해 정크 데이터가 삽입되었습니다. 새롭고 최적화 된 인덱스를 추가하기 전에 테이블을 MyISAM에서 InnoDB로 변환하고 정크 데이터가 포함 된 많은 행을 삭제하려고합니다.

데이터베이스는 MySQL 5.0이며 서버에 대한 루트 액세스 권한이 있습니다. 먼저 Adminer를 통해 이러한 명령을 실행 한 다음 phpMyAdmin을 동일한 결과로 실행했습니다.

내가 실행중인 명령은

DELETE
FROM `tablename`
WHERE `columnname` LIKE '-%'

기본적으로이 열에서 대시로 시작하는 모든 항목을 삭제하십시오 -.

약 3-5 분 동안 실행 한 다음 프로세스 목록을 볼 때 사라졌습니다.

그런 다음 달리기

SELECT *
FROM `tablename`
WHERE `columnname` LIKE '-%'

그리고 수백만 행을 반환합니다.

삭제 문장이 왜 완료되지 않습니까?

추신 : 나는 MySQL 5.0이 얼마나 오래된 지 알고 있습니다. DB를 MySQL 5.6 w InnoDB (MariaDB 10 w XtraDB)로 옮기는 작업을하고 있지만 그 때까지 DB를 그대로 사용하려고합니다.

-

편집이 제거되었습니다. 내 답변을 참조하십시오.

답변:


24

InnoDB 아키텍처를보십시오 (Percona CTO Vadim Tkachenko의 사진).

InnoDB 배관

삭제중인 행이 실행 취소 로그에 기록됩니다. ibdata1 파일은 삭제 기간 동안 현재 커지고 있습니다. mysqlperformanceblog.comReasons for run-away main Innodb Tablespace 에 따르면 :

  • 많은 거래 변경
  • 매우 긴 거래
  • 래깅 퍼지 스레드

귀하의 경우, 행 #을 삭제하기 때문에 이유 # 1이 실행 취소 공간과 함께 하나의 롤백 세그먼트를 차지합니다. 해당 행은 삭제가 완료 될 때까지 ibdata1에 있어야합니다. 해당 공간은 논리적으로 삭제되지만 디스크 공간은 줄어들지 않습니다.

지금 삭제를 종료해야합니다. 삭제 쿼리를 종료하면 삭제 된 행이 롤백됩니다.

대신이 작업을 수행하십시오.

CREATE TABLE tablename_new LIKE tablename;
INSERT INTO tablename_new SELECT * FROM tablename WHERE `columnname` NOT LIKE '-%';
RENAME TABLE
    tablename TO tablename_old,
    tablename_new TO tablename
;
DROP TABLE tablename_old;

먼저 MyISAM 버전의 테이블에 대해이 작업을 수행 할 수 있습니다. 그런 다음이를 InnoDB로 변환하십시오.


21

내 경우 에 필요한 답을 지나치게 복잡하게 만들었을지도 모른다 . 필자는 롤랜드와 릭 제임스 모두 임시 테이블을 생성하여 필터를 통과하는 행만 주입하는 것이 정확 NOT LIKE '-%'하지만 지금까지 알지 못했던 중요한 오류가 있었기 때문에 나를위한 솔루션은 더 쉬웠습니다. 사과합니다

mysql대화식 프롬프트 에서 쿼리를 실행하고 오류 메시지를 확인했습니다.

mysql> DELETE FROM `slugs` WHERE `slug` LIKE '-%';
ERROR 1206 (HY000): The total number of locks exceeds the lock table size

Googleing 오류를 통해 솔루션 을 파일을 innodb_buffer_pool_size통해 늘리고 /etc/my.cnfmysql 데몬을 재부팅하는 것이 발견되었습니다 . 내 서버의 경우이를 기본값으로 설정 8M하고 나는 그것을 증가 1G(서버가 32기가바이트 가지고 있으며, 이것은 현재 이노 유일한 테이블).

mysql> DELETE FROM `slugs` WHERE `slug` LIKE '-%';
Query OK, 23517226 rows affected (27 min 33.23 sec)

그런 다음 명령을 실행하고 ~ 27 분 안에 2,300 만 레코드를 삭제할 수있었습니다.

무엇 innodb_buffer_pool_size을 설정 해야하는지 궁금 하다면 RAM 용량을 기록한 다음 이 스레드 를 검토하여 제안 된 예상 용량 (GB)을 확인하십시오.


12

롤랜드의 제안은 한 번에 두 가지 작업을 모두 수행하여 가속화 될 수 있습니다.

CREATE TABLE tablename_new LIKE tablename;
ALTER TABLE tablename_new ENGINE = InnoDB;
INSERT INTO tablename_new 
    SELECT * FROM tablename WHERE `columnname` NOT LIKE '-%' ORDER BY primary_key;
RENAME TABLE
    tablename TO tablename_old,
    tablename_new TO tablename
;
DROP TABLE tablename_old;

: 그러나 여기 겉으로는 영원히 복용보다는 덩어리로 큰 h 제한하는 방법을 설명하는 블로그입니다 http://mysql.rjweb.org/doc.php/deletebig 요점은 1K을하고는 PK를 통해 테이블을 통해 도보로되어 한 번에 행. (물론 알아야 할 자세한 내용이 있습니다.)

그리고이 블로그는 InnoDB로 전환 할 때 발생할 수있는 잠재적 문제점을 다룹니다 : http://mysql.rjweb.org/doc.php/myisam2innodb


5

첫 번째 본능은 쿼리 결과 수를 제한하고 쿼리를 여러 번 실행하여 여러 번의 작은 삭제를 수행하는 것입니다.

DELETE
FROM `tablename`
WHERE `columnname` LIKE '-%' LIMIT 1000000

이 방법의 단점 : 각 삭제에는 시간이 오래 걸립니다. 이는와 일치하지 않는 점점 더 많은 행을 건너 뛰어야하기 때문 WHERE입니다.
Rick James

그러나이 프로세스가 너무 자주 발생하지 않으면 여러 번의 전체 테이블 스캔이 원래 문제가 해결되는 것만 큼 나쁘지 않아야합니다. 즉, 실행 취소 로그 크기로 인해 쿼리가 완료되지 않습니다.
kristianp

유효한 포인트. (저는 LIMIT낮추 겠습니다 . 10000이라고 말 하십시오 .)
Rick James

4

가장 쉬운 해결책은 단순히 그렇게하지 않는 것입니다. 더 작은 삭제를 수행하면 더 쉽게 처리 할 수 ​​있습니다.

이 경우 양식을 순차적으로 삭제하는 것이 좋습니다.

DELETE
FROM `tablename`
WHERE `columnname` LIKE '-a%'

2

아마도 당신은 이런 식으로 할 수 있습니다 :

  • 이라는 새 필드를 추가하십시오 deleted.
  • 와 같은 업데이트를 수행하십시오 UPDATE tablename SET deleted=1 WHERE `columnname` LIKE '-a%'.
  • cron야간에이를 삭제하도록 설정하십시오 .

삭제하는 데 업데이트 오래 걸릴 있습니다.
Rick James
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.