2014-02-14 2 views
0

그래, 쿼리가 간단합니다.mySQL 쿼리 최적화 (RANGE)

CREATE TABLE `ips` (
    `ip` int(11) unsigned NOT NULL DEFAULT '0', 
    `ip_start` int(11) unsigned NOT NULL DEFAULT '0', 
    `ip_end` int(11) unsigned NOT NULL DEFAULT '0', 
    KEY `IP` (`ip`), 
    KEY `IP_RANGE_END` (`ip_end`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

이 테이블은 (는 IP 열에서) 단일 IP를 하나 가득 또는 IP 범위 (ip_start ip_end 수) : 이것은에 저장되어있는 테이블입니다. 다음은

은 내가 사용하고있는 기능입니다 : 나는 현재 아마존의 RDS에이를 호스팅하고

CREATE DEFINER=`root`@`%` FUNCTION `in_adometry`(in_ip VARCHAR(30)) RETURNS int(11) 
    DETERMINISTIC 
BEGIN 

SET @ip = 0; 

SELECT COUNT(*) INTO @ip FROM ips WHERE (INET_ATON(in_ip) BETWEEN ip_start AND ip_end) OR ip = INET_ATON(in_ip) LIMIT 1; 

IF @ip > 0 THEN 
    RETURN 1; 
END IF; 

RETURN 0; 
END 

(중간 크기), 800 번째를 조회 한 후 CPU가 이상에 도달하기 전에 나는 더 이상 얻을 수 없다 100 %. 이 RDS에는이 테이블 하나 외에 다른 테이블이 없습니다. 110 만 개의 단일 IP가 있으며 그 다음으로 IP 범위가 약 3,000 개 (2 천만 개 이상의 IP가 함께)입니다. 이 속도를 높이려면 어떻게해야합니까?

답변

0

느린 쿼리에 대한 한 가지 가능한 이유는 (MySQL의 문서에서)입니다 : 당신은>, < = 같은 연산자를 사용하여 값의 범위를 (검사 쿼리를 실행하는 경우, 메모리 스토리지 엔진을 사용하는 테이블로

또는 인덱스 된 C 럼에서 BETWEEN) USING BTREE 절을 사용하여 인덱스를 작성하십시오. 기본값 (USING HASH)은 항등 연산자 (= 또는 < =>)를 사용하여 개별 행을 검색 할 때 빠르지 만 열 값 범위를 검사하는 데 훨씬 느립니다 (전체 테이블 스캔이 필요함). USING BTREE 절로 작성된 MEMORY 테이블은 동등한 비교를 위해 여전히 빠르기 때문에 다양한 절을 처리하는 MEMORY 테이블에이 절을 사용하십시오.

인덱스 유형을 변경하면 쿼리 속도가 크게 높아질 수 있습니다. 자세한 내용은 Avoid Full Table Scan을 읽으십시오.

+0

이것은 INNODB 테이블을 사용하고 있다는 사실과 관련이 있습니까? –

+0

에 EXPLAIN을 실행하십시오. 그러면 쿼리가 전체 테이블 스캔을 수행하는지 여부가 명확 해집니다. – RaviH

+0

아무 것도 전체 테이블 스캔, 내 두 인덱스에 union_join을하고있다. –

1

count(*)을 수행하는 것은 아마도 필요하지 않습니다. 이것을 시도하십시오 :

BEGIN 
IF exists (SELECT 1 
      FROM ips 
      WHERE INET_ATON(in_ip) BETWEEN ip_start AND ip_end OR ip = INET_ATON(in_ip) 
     ) 
THEN 
    RETURN 1; 
END IF; 

RETURN 0;