2014-07-14 3 views
4

많은 많은 사용자가 24 시간 액세스 할 수있는 MySQL 5.6 데이터베이스가있는 웹 포럼 응용 프로그램이 있다고합시다. 이제 사용자에게 전송되는 알림의 메타 데이터에 대해 이와 같은 표가 있습니다.인덱스가 큰 MySQL 테이블에서 성능이 저하되었습니다

| notifications | CREATE TABLE `notifications` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 
`user_id` bigint(20) unsigned NOT NULL, 
`message_store_id` bigint(20) unsigned NOT NULL, 
`status` varchar(10) COLLATE ascii_bin NOT NULL, 
`sent_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
PRIMARY KEY (`id`), 
KEY `user_id` (`user_id`,`sent_date`) 
) ENGINE=InnoDB AUTO_INCREMENT=736601 DEFAULT CHARSET=ascii COLLATE=ascii_bin | 

이 테이블에는 100 만 개의 행이 있습니다. 이 테이블로, 특정 message_store_id은 어떤 이유로 갑자기 효과가되어 나는이 하나의 문이 있기 때문에 테이블의 10 %에 영향을 미치는

DELETE FROM notifications WHERE message_store_id = 12345; 

같은 단일 삭제 문이 message_store_id으로 모든 레코드를 제거 할 계획입니다 많은 사용자에게 메시지가 전송되었습니다. 이 알림 테이블은 수천 명의 사용자가 항상 액세스하므로 인덱스가 있어야합니다. 분명히 인덱스 레크 리 에이션은 레코드를 삭제할 때 매우 비용이 많이 드는 것이므로 서버 리소스를 최대한 활용하여 시간을 절약 할 수 있습니다. 그러나 인덱스를 삭제하고 레코드를 삭제 한 다음 인덱스를 다시 추가하면 언젠가 데이터베이스를 종료해야하지만 불행히도 서비스가 불가능합니다.

나는이 5.6이 데이터베이스를 죽일 수있는 바보가 아니기를 바랄 뿐이지 만 가능성은 매우 높다고 생각한다. 제 질문은이 경우에 대비해 인덱스 재현이 정말로 치명적입니까? 그렇다면 유지 관리를 위해 데이터베이스를 중지 할 필요가없는이 작업을위한 좋은 전략이 있습니까?

+0

'message_store_id'에 색인이 있습니까? – cmorrissey

답변

2

응용 프로그램의 세부 사항에 따라 사용할 수있는 많은 트릭/전략이있을 수 있습니다. 정기적으로 이러한 작업을 수행하려는 경우

  1. (예를 들면 그것은 한 번 일이 아니다), 당신은 당신이 파티션을 사용할 수 message_store_id에 몇 가지 고유 한 값을 가지고있다. message_store_id의 값으로 파티션을 나누려면 미리 X 파티션을 만들고 (여기서 X는 ID 값의 합리적인 한계입니다) 그 파티션을 자르면 해당 파티션의 모든 레코드를 즉시 삭제할 수 있습니다. 밀리 세컨드의 문제. 단점 : message_store_id은 기본 키의 일부 여야합니다. 참고 : 이전에 파티션을 작성해야합니다. 이전에 작업했을 때 alter table add partition이 전체 테이블을 다시 작성했기 때문에 큰 테이블에 재앙이되었습니다.
  2. alter table truncate partition이 제대로 작동하지 않더라도 분할 작업을 계속 수행 할 수 있습니다. 해당 where 조건을 제공하여 파티션에서 DELETE을 실행하면 나머지 테이블은이 DELETE op에 의해 영향 받거나 잠기지 않습니다. 너무 오랫동안 DB를 잠그지 않고 기록을 삭제
  3. 대체 방법 :

    while (true) { 
        // assuming autocommit mode 
        delete from table where {your condition} limit 10000; 
        // at this moment locks are released and other transactions have a chance 
        // to do some stuff. 
        if (affected rows == 0) { 
        break; 
        } 
        // This is a good place to insert sleep(5) to give other transactions 
        // more time to do their stuff before the next chunk gets deleted. 
    } 
    
0

하나의 옵션은이 같은 여러 개의 작은 작업보다는 하나 개의 거대한 삭제 작업을 수행하는 것입니다.

MySQL은 LIMIT 절을 제공합니다.이 절은 쿼리와 일치하는 행 수를 제한합니다.

예를 들어, 당신은 단지 1000 행을 삭제할 수 :

DELETE FROM notifications WHERE message_store_id = 12345 LIMIT 1000; 

당신은 완료 (같은 테이블에 잠금 경쟁) 다른 작업 시간의 적절한 창을 떠나, 그 반복 할 수있다.순수 SQL에서이 문제를 처리하기 위해, 우리는 예를 들어, 2 초간 일시 정지, MySQL의 SLEEP() 기능을 사용할 수 있습니다 :

SELECT SLEEP(2); 

그리고 분명히,이 루프에 통합 할 수 있습니다를, MySQL의 과정에서, 예를 들어, DELETE 문이 0 행에 영향을 줄 때까지 계속 반복합니다.

관련 문제