Как я могу оптимизировать этот запрос ...? - PullRequest
3 голосов
/ 26 июня 2009

У меня есть две таблицы, одна для маршрутов и одна для аэропортов.

Маршруты содержат чуть более 9000 строк, и я проиндексировал каждый столбец. В аэропортах только 2000 строк, и я также проиндексировал каждый столбец.

Когда я запускаю этот запрос, для возврата 300 строк может потребоваться до 35 секунд:

SELECT routes.* , a1.name as origin_name, a2.name as destination_name FROM routes
LEFT JOIN airports a1 ON a1.IATA = routes.origin
LEFT JOIN airports a2 ON a2.IATA = routes.destination
WHERE routes_build.carrier = "Carrier Name"

Запустив его с «DESCRIBE», я получаю следующую информацию, но я не на 100% уверен в том, что она говорит мне.

id | Select Type   | Table             | Type   | possible_keys        | Key            | Key_len   | ref    | rows     | Extra
--------------------------------------------------------------------------------------------------------------------------------------
1  | SIMPLE        | routes_build      | ref    | carrier,carrier_2    | carrier        | 678       | const  | 26       | Using where
--------------------------------------------------------------------------------------------------------------------------------------
1  | SIMPLE        | a1                | ALL    | NULL                 | NULL           | NULL      | NULL   | 5389     |
--------------------------------------------------------------------------------------------------------------------------------------
1  | SIMPLE        | a2                | ALL    | NULL                 | NULL           | NULL      | NULL   | 5389     |
--------------------------------------------------------------------------------------------------------------------------------------

Единственная альтернатива, о которой я могу подумать, - это запустить два отдельных запроса и соединить их с PHP, хотя я не могу поверить, что что-то подобное может убить сервер mysql. Так что, как обычно, я подозреваю, что делаю что-то глупое. SQL - моя слабость номер 1.

Ответы [ 5 ]

3 голосов
/ 26 июня 2009

Лично я бы начал с удаления левых объединений и замены их внутренними объединениями, поскольку каждый маршрут должен иметь начальную и конечную точки.

1 голос
/ 26 июня 2009

Это говорит о том, что он не использует индекс для присоединения к таблице аэропортов. Видите, как огромен столбец "Строки", 5000 с лишним? вот сколько строк нужно прочитать, чтобы ответить на ваш запрос.

Я не знаю почему, поскольку вы утверждали, что проиндексировали каждый столбец. Что такое ИАТА? Это уникальный? Я считаю, что если mysql решит, что индекс неэффективен, он может его игнорировать.

РЕДАКТИРОВАТЬ: если IATA является уникальной строкой, может быть, попробуйте проиндексировать только половину? (Вы можете выбрать количество символов для индексации) Это может дать mysql индекс, который он может использовать.

1 голос
/ 26 июня 2009
SELECT  routes.*, a1.name as origin_name, a2.name as destination_name
FROM    routes_build
LEFT JOIN
        airports a1
ON      a1.IATA = routes_build.origin
LEFT JOIN
        airports a2
ON      a2.IATA = routes_build.destination
WHERE   routes_build.carrier = "Carrier Name"

Из вашего EXPLAIN PLAN Я вижу, что у вас нет индекса на airports.IATA.

Вы должны создать его, чтобы запрос работал быстро.

Имя также предполагает, что это должен быть индекс UNIQUE, поскольку IATA коды являются уникальными.

Обновление:

Пожалуйста, опубликуйте определение таблицы. Выполните этот запрос, чтобы показать его:

SHOW CREATE TABLE airports

Также я должен отметить, что ваш индекс FULLTEXT для IATA бесполезен, если вы не установили ft_max_word_len в конфигурации MySQL на 3 или меньше.

По умолчанию это 4.

IATA коды имеют длину 3 символов, и MySQL не ищет такие короткие слова, используя FULLTEXT с настройками по умолчанию.

0 голосов
/ 26 июня 2009

Это действительно зависит от того, какую информацию вы пытаетесь получить. Вам, вероятно, не нужно присоединяться к аэропорту дважды, и вам, вероятно, не нужно использовать левое соединение. Кроме того, если вы можете выполнять поиск по числовому полю, а не по текстовому полю, это также ускорит процесс.

Так что вы пытаетесь получить?

0 голосов
/ 26 июня 2009

После того, как вы реализуете отличный совет Мартина Робинса (то есть удалите каждый экземпляр слова LEFT из своего запроса), попробуйте дать routes_build составной индекс для carrier, origin и destination.

...