Логика выполнения 2х селектов в MySQL

Довелось разбираться с GeoIP. Начинал с этого топика, в итоге скачал и распарсил базу maxmind.

Структура таблицы:
CREATE TABLE IF NOT EXISTS `geoip_block` (
`BlockId` int(11) unsigned NOT NULL AUTO_INCREMENT,
`StartNum` int(11) unsigned NOT NULL,
`EndNum` int(10) unsigned NOT NULL,
`LocationId` int(10) unsigned NOT NULL,
PRIMARY KEY (`BlockId`),
KEY `GeoIp_StartNum` (`StartNum`),
KEY `GeoIp_EndNum` (`EndNum`),
KEY `GeoIp_LocationId` (`LocationId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=3620778 ;


Количество записей:
mysql> SELECT count(BlockId) FROM geoip_block;
+----------------+
| count(BlockId) |
+----------------+
| 3620777 |
+----------------+
1 row in set (0.00 sec)


Выполняю 2 запроса:
mysql> SELECT SQL_NO_CACHE LocationId FROM geoip_block where StartNum<=1385960996 and EndNum>=1385960996 LIMIT 1;
+------------+
| LocationId |
+------------+
| 161 |
+------------+
1 row in set (5.20 sec)


И
mysql> SELECT SQL_NO_CACHE LocationId FROM (SELECT * FROM geoip_block WHERE StartNum <=1385960996 ORDER BY StartNum DESC LIMIT 1) AS T WHERE EndNum >=1385960996;
+------------+
| LocationId |
+------------+
| 161 |
+------------+
1 row in set (0.0006 sec)


Видим, что разница во времени выполнения — огромная.

Explain результата не дает особо:
mysql> EXPLAIN SELECT SQL_NO_CACHE LocationId FROM geoip_block where StartNum<=1385960996 and EndNum>=1385960996 LIMIT 1;
+----+-------------+-------------+-------+-----------------------------+----------------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------+-------+-----------------------------+----------------+---------+------+---------+-------------+
| 1 | SIMPLE | geoip_block | range | GeoIp_StartNum,GeoIp_EndNum | GeoIp_StartNum | 4 | NULL | 1810530 | Using where |
+----+-------------+-------------+-------+-----------------------------+----------------+---------+------+---------+-------------+
1 row in set (0.01 sec)


mysql> EXPLAIN SELECT SQL_NO_CACHE LocationId FROM (SELECT * FROM geoip_block WHERE StartNum <=1385960996 ORDER BY StartNum DESC LIMIT 1) AS T WHERE EndNum >=1385960996;
+----+-------------+-------------+--------+----------------+----------------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------+--------+----------------+----------------+---------+------+---------+-------------+
| 1 | PRIMARY | | system | NULL | NULL | NULL | NULL | 1 | |
| 2 | DERIVED | geoip_block | range | GeoIp_StartNum | GeoIp_StartNum | 4 | NULL | 1810530 | Using where |
+----+-------------+-------------+--------+----------------+----------------+---------+------+---------+-------------+
2 rows in set (0.00 sec)


Вопрос: Как MySQL делает обход таблицы в случае с "<= AND =>" (ps: с BETWEEN тот же результат)?
  • Вопрос задан
  • 2779 просмотров
Пригласить эксперта
Ответы на вопрос 3
vinxru
@vinxru
Ответ: Она не использует индекс.

Если бы она использовала индекс, то в поле Explain (для select_type=SIMPLE) содержался бы текст «Using where; Using index;».
Ответ написан
xiWera
@xiWera
А несмущает отсутствие NO_CACHE в подзапросе второго запроса. Собственно внешний NO_CACHE при этом никакого значения не имеет.
Ответ написан
archibaldtelepov
@archibaldtelepov
Кроме того, no_cache это интересно, но в первом запросе могут быть ещё данные только на диске.
а во втором запросе может оказаться так, что данные уже в кэше дисковой подсистемы, например

Попробуйте выполнить запросы на свежем сервере в обратном порядке?
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы