2011-09-19 3 views
0

내가 (장고에 의해) 생성됩니다 쿼리가의 터무니없는 금액을 :쿼리는 다음과 같이 시간

SELECT `geo_ip`.`id`, `geo_ip`.`start_ip`, 
     `geo_ip`.`end_ip`, `geo_ip`.`start`, 
     `geo_ip`.`end`, `geo_ip`.`cc`, `geo_ip`.`cn` 
FROM `geo_ip` 
WHERE (`geo_ip`.`start` <= 2084738290 AND `geo_ip`.`end` >= 2084738290) 
LIMIT 1 

그것은 거기에 134,189 항목으로의 지리적 위치 테이블을 쿼리합니다. 인덱스가 추가 될 때마다 각 쿼리에서 100 밀리 초가 걸리므로 여러 가지 일회용으로 사용할 수 없게됩니다. 나는 IP 조회를 한 번만해야하므로 응답을 캐싱 할 것입니다. 그러나 내가 더 빨리 그것을 만드는 확실한 방법이 없다면 궁금합니다. 내 테이블 :

CREATE TABLE `geo_ip` (
    `start_ip` char(15) NOT NULL, 
    `end_ip` char(15) NOT NULL, 
    `start` bigint(20) NOT NULL, 
    `end` bigint(20) NOT NULL, 
    `cc` varchar(6) NOT NULL, 
    `cn` varchar(150) NOT NULL, 
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    PRIMARY KEY (`id`), 
) ENGINE=InnoDB AUTO_INCREMENT=134190 DEFAULT CHARSET=latin1 

과 같이 두 컬럼에 인덱스를 만들기 :

ALTER TABLE geo_ip ADD INDEX (start, end); 

을 제공합니다 다음과 같은 설명 :

:

EXPLAIN SELECT geo_ip.id, geo_ip.start_ip, geo_ip.end_ip, 
       geo_ip.start, geo_ip.end, geo_ip.cc, geo_ip.cn 
FROM geo_ip 
WHERE (geo_ip.end >= 2084738290 AND geo_ip.start < 2084738290) 
LIMIT 1; 
+----+-------------+--------+-------+---------------+-------+---------+------+-------+----------+-------------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra  | 
+----+-------------+--------+-------+---------------+-------+---------+------+-------+----------+-------------+ 
| 1 | SIMPLE  | geo_ip | range | start   | start | 8  | NULL | 67005 | 100.00 | Using where | 
+----+-------------+--------+-------+---------------+-------+---------+------+-------+----------+-------------+ 

그것은 선택을 완료하는 데 훨씬 넘는이 100ms 소요

SELECT geo_ip.id, geo_ip.start_ip, geo_ip.end_ip, 
     geo_ip.start, geo_ip.end, geo_ip.cc, 
     geo_ip.cn 
FROM geo_ip 
WHERE (geo_ip.end >= 2084738290 and geo_ip.start < 2084738290) 
LIMIT 1; 
+-------+--------------+----------------+------------+------------+----+-----------+ 
| id | start_ip  | end_ip   | start  | end  | cc | cn  | 
+-------+--------------+----------------+------------+------------+----+-----------+ 
| 51725 | 124.66.128.0 | 124.66.159.255 | 2084732928 | 2084741119 | SG | Singapore | 
+-------+--------------+----------------+------------+------------+----+-----------+ 
1 row in set (0.18 sec) 

더 많은 expensi 이러한 요청을 완료 할

ALTER TABLE geo_ip ADD INDEX (`start`); 
ALTER TABLE geo_ip ADD INDEX (`end`); 
+----+-------------+--------+-------+---------------+-------+---------+------+-------+-------------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra  | 
+----+-------------+--------+-------+---------------+-------+---------+------+-------+-------------+ 
| 1 | SIMPLE  | geo_ip | range | start,end  | start | 8  | NULL | 68017 | Using where | 
+----+-------------+--------+-------+---------------+-------+---------+------+-------+-------------+ 

그것은 약 100ms의 소요 : 한 개인 인덱스를하는 것보다했습니다

SELECT geo_ip.id, geo_ip.start_ip, geo_ip.end_ip, geo_ip.start, geo_ip.end, geo_ip.cc, geo_ip.cn FROM geo_ip 
WHERE (geo_ip.end >= 2084738290 AND geo_ip.start < 2084738290) limit 1; 
+-------+--------------+----------------+------------+------------+----+-----------+ 
| id | start_ip  | end_ip   | start  | end  | cc | cn  | 
+-------+--------------+----------------+------------+------------+----+-----------+ 
| 51725 | 124.66.128.0 | 124.66.159.255 | 2084732928 | 2084741119 | SG | Singapore | 
+-------+--------------+----------------+------------+------------+----+-----------+ 
1 row in set (0.11 sec) 

는 그러나 이러한 방법 모두가 너무 오래 걸릴, 그것은 이것에 대해 아무것도 할 수 있습니까?

답변

0

시간은 항상 "where"절에서 소비됩니다.

"보다 낮음"또는 "보다 큼"으로 두 개의 다른 필드에서 작업하기 때문에 원하는 레코드를 찾기 위해 많은 인덱스를 읽어야합니다.

나는 이런 식으로 내 테이블을 했어야 :이 선택할 수 있도록

+-------+-------+----------------+------------+----+-----------+ 
| id | type | ip    | geo  | cc | cn  | 
+-------+-------+----------------+------------+----+-----------+ 
| 51725 | start | 124.66.159.255 | 2084732928 | SG | Singapore | 
+-------+-------+----------------+------------+----+-----------+ 
| 51726 | end | 124.66.159.255 | 2084732928 | SG | Singapore | 
+-------+-------+----------------+------------+----+-----------+ 

을 :

select * from table where geo between '2084732927' and '2084732928' 

을 지리에 대한 인덱스와 함께. 훨씬 빨라야합니다. 그러나 미안하지만, 나는 시험 할 시간이 없다.