2013-07-11 1 views
0

크롤링 할 URI 목록을 저장하는 테이블이 있습니다. 이 'crawl_index'테이블 스키마는 다음과 같습니다이 테이블에 대한MySQL - "Group by"의 성능 문제

CREATE TABLE `crawl_index` (
    `id`    INTEGER(10) NOT NULL AUTO_INCREMENT, 
    `uri`    TEXT   NOT NULL, 
    `domain`   VARCHAR(255) NOT NULL, 
    `last_crawled_date` INTEGER(10) NOT NULL DEFAULT 0, 
    PRIMARY KEY (`id`), 
    INDEX `crawler_INDEX_1` (`domain`), 
    INDEX `crawler_INDEX_2` (`last_crawled_date`) 
) ENGINE=InnoDB; 

일부 세부 정보 :

  • 가 약 1M 행이 포함되어 있습니다.
  • 거의 60 %의 행에 "last_crawled_date"가 0으로 설정되어 있습니다 (크롤링 된 페이지에서 실제로 페이지를 크롤링하는 것보다 URI를 추출하는 것이 빠릅니다).
  • "id"필드는 사용되지 않습니다. 내가 바인딩되지 않은 텍스트이기 때문에 나는 "uri"필드에 기본 키를 만들 수 없으므로 명시적인 primary_key를 갖는 스키마에만 추가합니다.

    • URI가 이미되어 나는 모든 반환을하지 않으려는
    • 지난 2 일 내에 기어 안 : 내가 원하는 무엇

    는 다음과 같은 제약 N 행을 선택하는 것입니다 동시에 동일한 도메인에서 너무 많은 요청을하지 않도록 동일한 도메인에서 오는 URI. 그것은 나에게 이런 종류의 결과 제공

    select * from crawl_index where last_crawled_date <= 1373273029 group by domain limit 3; 
    

    :

    +--------+------------------------+--------------+-------------------+ 
    | id  | uri     | domain  | last_crawled_date | 
    +--------+------------------------+--------------+-------------------+ 
    | 60239 | http://example1.com/1 | example1.com |     0 | 
    | 239 | http://example2.com/1 | example2.com |     0 | 
    | 120239 | http://example3.com/1 | example3.com |     0 | 
    +--------+------------------------+--------------+-------------------+ 
    3 rows in set (1,23 sec) 
    

    그것은 작동을하지만은 않고 동일한 쿼리에 비해 매우 느린 순간

, 나는이 쿼리를 시도 "group by"성명서.

+----+-------------+-------------+-------+-----------------+-----------------+---------+------+-------+-----------------------+ 
| id | select_type | table  | type | possible_keys | key    | key_len | ref | rows | Extra     | 
+----+-------------+-------------+-------+-----------------+-----------------+---------+------+------+------------------------+ 
| 1 | SIMPLE  | crawl_index | range | crawler_INDEX_1 | crawler_INDEX_2 | 4  | NULL | 71588 | Using index condition | 
| |    |    |  | crawler_INDEX_2 |     |   |  |  | Using temporary  | 
| |    |    |  |     |     |   |  |  | Using filesort  | 
+----+-------------+-------------+-------+-----------------+-----------------+---------+------+-------+-----------------------+ 

이미 I : : 그 쿼리에 explain를 실행하면,이 가지고

  • 이 LAST_CRAWLED_DATE 및 도메인 필드에 인덱스를 만들
  • 이 날짜 비교를 피하기 위해 내 LAST_CRAWLED_DATE를 저장하는 정수를 사용을
  • 은 PHP 코드에서 max_date를 미리 계산하여 mysql이 나를 대신하도록 요구하지 않도록합니다.

이 쿼리를 향상시킬 수있는 아이디어가 있습니까? 사용

답변

0

filesort

이 문제입니다. 사용하는 DB 엔진의 메모리 제한을 늘릴 수 있습니다.

다른 해결책은 VARCHAR(255) 대신 도메인 열에서 ENUM을 사용할 수 있습니까?

+0

크롤링 할 새 도메인을 추가 할 때마다 스키마를 업데이트해야하므로 'ENUM'을 사용할 수 없습니다. 메모리 제한을 늘리는 것이 좋습니다.나는 그것을 시험해보고 그것이 퍼포먼스가 증가했는지를 말해 줄 것이다. 하지만 지금은, Im이 왜 "파일", "임시"및 "색인"을 더 이상 사용하지 않고 그냥 "어디에서"사용 하는지를 설명하는 suddently 이유를 이해하려고합니다. 단지 내가 변경 한 것은 생산 제한을 시뮬레이션하기 위해 내 테이블에 수십만 개의 uris가 있습니다. 응답 시간은 기본적으로 1.5 초에서 2 초 사이입니다. 이상한... – Remi

1

(last_crawled_date, domain)에 합성 색인을 작성하고 Explain 플랜을보십시오. 실행 시간을 줄여야합니다. 다른 색인도 제거하고 테스트하십시오.