2017-12-03 17 views
0

"대기열"이라는 큰 테이블이 있습니다. 현재 1,200 만 레코드가 있습니다.MySQL 성능 - 큰 테이블에서 선택 및 삭제

CREATE TABLE `queue` (
    `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 
    `userid` varchar(64) DEFAULT NULL, 
    `action` varchar(32) DEFAULT NULL, 
    `target` varchar(64) DEFAULT NULL, 
    `name` varchar(64) DEFAULT NULL, 
    `state` int(11) DEFAULT '0', 
    `timestamp` int(11) DEFAULT '0', 
    `errors` int(11) DEFAULT '0', 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `idx_unique` (`userid`,`action`,`target`), 
    KEY `idx_userid` (`userid`), 
    KEY `idx_state` (`state`) 
) ENGINE=InnoDB; 

다중 PHP 작업자 (150)는 동시에,이 테이블을 사용한다.

레코드를 선택하고 선택한 데이터를 사용하여 네트워크 요청을 수행 한 다음 레코드를 삭제합니다.

선택 및 삭제 쿼리에서 실행 시간이 혼합되었습니다. 삭제 명령이 테이블을 잠그고 있습니까?

이 시나리오에 가장 적합한 방법은 무엇입니까?

  1. SELECT 기록 + 네트워크 요청 + 기록을 삭제

  2. 는 SELECT 기록 + 네트워크 요청 + 수시로 크론을 사용하여 완료 + Delete를 완료 기록과 같은 MARK 레코드 (나는 심지어 원하지 않는 큰 테이블).

참고 : 큐는 매분마다 새 레코드를 가져 오지만 INSERT 쿼리는 여기에서 문제가되지 않습니다.

도움을 주시면 감사하겠습니다.

+1

데이터베이스를 대기열로 사용하고 여러 클라이언트에서 작업하는 경우 잠금 경합에 부딪치게됩니다. 데이터베이스를 대기열로 사용하려고하면 모든 사람이이 작업에 어려움을 겪습니다. 대신 데이터베이스가 아닌 실제 메시지 큐 소프트웨어를 사용해야합니다. ActiveMQ 또는 Beanstalkd 또는 RabbitMQ 또는 Resque와 같은 것입니다. –

+1

특히 쿼리 성능에 관한 부분을 읽으면 도움이 될 것입니다. http://meta.stackoverflow.com/a/271056/ 그런 다음 질문을 편집하여 세부 정보를 제공 할 수 있습니다. –

답변

1

"대기열에 넣지 마라, 그냥해라". 즉, 작업이 빠른 경우 작업을 수행하고 대기열에 넣지 않는 것이 좋습니다. 데이터베이스는 좋은 큐 메커니즘을 만들지 않습니다.

DELETE InnoDB 테이블을 잠그지 않습니다. 그러나, 그게 장난스럽게 보이는 DELETE을 쓸 수 있습니다. 실제 SQL을보고 개선 할 수 있도록 노력하겠습니다.

12M 레코드? 그것은 거대한 백 로그입니다. 무슨 일이야?

  • action 가능한 값의 작은 집합이다 : 표하지 기가되도록

    는 데이터 유형을 축소? 1 바이트 ENUM 또는 TINYINT UNSIGNED으로 표준화하십시오.

  • state에 대한 Ditto - 반드시 4 바이트 코드가 필요하지 않습니까?
  • userid으로 시작하는 색인 ​​(UNIQUE)이 이미 있으므로 INDEX(userid)은 필요하지 않습니다.
  • state의 값이 몇 개인 경우 인덱스가 사용되지 않습니다. 우리가 그 인덱스를 제거하거나 '복합적으로'(그리고 유용하게) 만드는 방법을 논의 할 수 있도록 enqueue 및 dequeue 쿼리를 살펴 봅시다.
  • MAX(id)의 현재 값은 무엇입니까? INT UNSIGNED에 대해 현재 약 40 억을 초과 할 것으로 위협됩니까?
  • PHP는 어떻게 큐를 사용합니까? InnoDB 트랜잭션을 통해 항목에 매달려 있습니까? 그것은 어떤 병렬 처리도 무효로합니다! 또는 state을 변경합니까? 코드를 보여주세요. 잠금 장치 & 잠금 해제는 덜 침략 적으로 만들 수 있습니다. 하나의 자동 커밋 된 UPDATE을 실행하여 행을 가져와 id을 실행할 수 있어야합니다.그런 다음 나중에 자동 적용된 DELETE을 사용하여 거의 영향을주지 않습니다.
  • 보류중인 항목을 가져 오는 데 필요한 좋은 인덱스가 없습니다. 다시 한 번 코드를 살펴 보겠습니다.
  • 150이 많은 것처럼 보입니다. 실험 해본 결과 은 (는)입니까? 그들은 일 수 있습니다.
  • 슬로우 로그가 켜져 있습니까 (long_query_time의 값이 낮습니까?)? 그렇다면 '최악의'쿼리가 무엇인지 궁금합니다. 이와 같은 상황에서 그 답은 놀랄 수 있습니다.
+0

제안 해 주셔서 감사합니다. 먼저 제안 된 변경 사항 중 일부를 구현하고 몇 가지 결과가 나타날 것입니다. 다시 감사합니다! –

+0

* 열 작용은 7 가지 값을 가지고 * 열 상태는 2 가지 값을 가지고 * 맥스 (ID)는 약 64,577,039 * 노동자 만 (그들의 작업 겹치지 않는) 아이디의 150 % = 0 태스크 peform받는 것이다 * 각 작업에 약 2 초가 걸리고 새 작업이 큐에 지속적으로 추가되므로 많은 수의 작업자가 실행해야합니다. –

+0

I/O 바인딩입니까? CPU 바인딩? 양자 모두? 노동자들은 같은 기계에 있습니까? 다른 기계 하나? 몇 가지 다른 기계? 2 초마다 150 개의 항목을 소비하고 있습니까? 대기열에 포함되는 속도입니까? –