оптимизация запроса SELECT (не используются индексы)

QuadMan

Новичок
оптимизация запроса SELECT (не используются индексы)

Здравствуйте!
Пытаюсь разобраться с MySQL, но уже, честно говоря, совсем запустался. Прошу вашей помощи! :)
Есть две таблицы.
Первая (большая таблица на 2,5 миллионов записей):
CREATE TABLE `table1` (
`IPN1` int(10) unsigned zerofill NOT NULL default '0000000000',
`IPN2` int(10) unsigned zerofill NOT NULL default '0000000000',
`CTRY` char(2) NOT NULL default '',
KEY `IPN2` (`IPN2`),
KEY `IPN1` (`IPN1`)
);
Вторая (небольшая - около 1000 записей):
CREATE TABLE `table2` (
`IP` int(10) unsigned zerofill NOT NULL default '0000000000',
PRIMARY KEY (`IP`)
);

Пишу запрос SELECT, который для каждой записи из table2 находит запись из table1 такую, что table2.IP>table1.IPN1 AND table2.IP<table1.IPN2.

Запрос следующий:
SELECT table1.CTRY from table1,table2 WHERE table2.IP BETWEEN table1.IPN1 AND table1.IPN2

но он выполняется жутко медленно - отбирает 3 записи за 30 секунд!!!

EXPLAIN SELECT дает, что
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE table2 index PRIMARY PRIMARY 4 NULL 441 Using index
1 SIMPLE table1 ALL NULL NULL NULL NULL 2459642

т.е. почему-то для table1 он не хочет использовать индексы, видимо проблема в этом. Подскажите - почему он не хочет производить поиск с учетом построенных индексов?

Заранее спасибо!
 

QuadMan

Новичок
Я думал, что они позволят быстрее сравнивать значения.. нет?
 

algo

To the stars!
Может, через вложенный селект ? Типа чтоб оно сначала по меньшему IP отсекало, а потом - по большему.. Ваще зависит от данных - какие данные такой и правильный план нада делать... :/
 

QuadMan

Новичок
Данные - IP - численное представление IP адреса - беззнаковое целое, 4 байта.
 

QuadMan

Новичок
Вот так?
SELECT table1.CTRY from table1,table2 WHERE (table2.IP < (SELECT table1.IPN2 FROM table1 WHERE table2.IP > table1.IPN1))

но MySQL на это ругается: Subquery returns more than 1 row...
никогда не использовал подзапросов... в чем я ошибся?
 

Gas

может по одной?
Попробуй такой запрос:

[SQL]
select g.*, ip
from (
select t.*,
(SELECT ipn2
from table1
where ipn2 > t.ip
ORDER BY ipn2
LIMIT 1) as ipn2
from table2 as t) as r
join table1 as g on r.ipn2=g.ipn2
having IF (ipn1 < ip, 1, 0);
[/SQL]

только лучше в table1 убей индекс IPN1, а IPN2 сделай уникальным ключём.

-~{}~ 16.07.07 12:06:

если table2 меняется не часто, то стоит вообще кешировать результат
 

Wicked

Новичок
попробуй в 1й таблице сделать один тройной индекс (ipn1, ipn2, ctry).

Кстати, я так понимаю, задача из разряда geoip. Она уже не раз обмусоливалась на форуме, в том числе с точки производительности.
 

Gas

может по одной?
Тройной индекс? Ну имхо это имеет смысл если таблица myisam и есть память чтоб загрузить весь её индекс туда для уменьшения дисковых операций.

одно из обмусоливаний
 

Wicked

Новичок
Gas
Ну двойной индекс скорее всего нужен для того, чтобы он вообще хоть как-то работал с between. Расширение до тройного - имхо желательно, если хочется видеть "Using index" в колонке Extra результата Explain'а:
The column information is retrieved from the table using only information in the index tree without having to do an additional seek to read the actual row. This strategy can be used when the query uses only columns that are part of a single index.
Т.е. кол-во дисковых операций так и так уменьшается, даже если не грузить индекс в память.
 

Alexandre

PHPПенсионер
Может, через вложенный селект ? Типа чтоб оно сначала по меньшему IP отсекало, а потом - по большему..
все зависит от типа индекса, но простые индексы (MyISAM) для операций поиска по диапазону (больше, меньше и BETWEEN) не работают, так как основаны на хешировании индексируемого поля (HashTable), т.е. идет сравнение хеш поля - индекс.
 

Gas

может по одной?
Wicked
это всё понятно, но варианты с поиском по диапазону работают "намного медленее" (проверялось - в разы) чем, вариант предложенный
hermit_refined
 

nail

Новичок
В table2 лучше добавить поле CTRY, то есть сделать денормализацию. Тогда все будет быстро и пушисто.
 

dadoc

Новичок
Автор оригинала: Alexandre
все зависит от типа индекса, но простые индексы (MyISAM) для операций поиска по диапазону (больше, меньше и BETWEEN) не работают, так как основаны на хешировании индексируемого поля (HashTable), т.е. идет сравнение хеш поля - индекс.
Что значит "простые индексы"? В myisam используются B-trees для построения индексов которые могут быть использованы для поиска по диапазону.
 

Vitafresh

Новичок
А в чем смысл этого запроса? Может быть имеет смысл пересмотреть структуру исходных таблиц?
 
Сверху