SQL-запрос объединяет несколько таблиц - слишком медленно (8 таблиц) - PullRequest
33 голосов
/ 30 апреля 2009

Я пытаюсь объединить 8 таблиц в одну для создания индекса, используемого другим приложением, мой запрос выглядит так: (мой навык mysql очень любительский)

SELECT t1_id, t2_name, t3_name, t4_name, t5_name, 
       t6_name, t7_name, t8_name, t9_name 
FROM t1 
  LEFT JOIN t2 ON (t1_id = t2_id) 
  LEFT JOIN t3 ON (t3_id = t1_id) 
  LEFT JOIN t4 ON (t4_id = t1_id)
  LEFT JOIN t5 ON (t5_id = t1_id)
  LEFT JOIN t6 ON (t6_id = t1_id) 
  LEFT JOIN t7 ON (t7_id = t1_id)
  LEFT JOIN t8 ON (t8_id = t1_id)
  LEFT JOIN t9 ON (t9_id = t1_id)

Я даже не вижу результатов запроса при его выполнении, есть ли способы ускорить его? :) приветствуется любая помощь, но лучше всего один запрос (вне правил приложения)

спасибо заранее

Ответы [ 8 ]

53 голосов
/ 16 июня 2009

У меня была похожая проблема с несколькими таблицами поиска, соединяющимися с большой таблицей с индексированными всеми полями идентификатора. Чтобы отслеживать влияние объединений на время выполнения запроса, я запускал свой запрос несколько раз (ограничиваясь первыми 100 строками), каждый раз добавляя соединение в дополнительную таблицу. После объединения 12 таблиц не было значительных изменений во времени выполнения запроса. К тому времени, когда я присоединился к 13-му столу, время выполнения подскочило до 1 секунды; 14-й стол 4 секунды, 15-й стол 20 с, 16-й 90 секунд.

Предложение Кейро использовать коррелированные подзапросы вместо объединений, например,

SELECT t1_id, 
        (select t2_name from t2 where t1_id = t2_id), 
        (select t3_name from t3 where t1_id = t3_id), 
        (select t4_name from t4 where t1_id = t4_id), 
        (select t5_name from t5 where t1_id = t5_id), 
        (select t6_name from t6 where t1_id = t6_id), 
        (select t7_name from t7 where t1_id = t7_id), 
        (select t8_name from t8 where t1_id = t8_id), 
        (select t9_name from t9 where t1_id = t9_id)  FROM t1

значительно улучшена производительность запросов. На самом деле подзапросы, похоже, не удлиняют время выполнения запроса (запрос был почти мгновенным).

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

28 голосов
/ 30 апреля 2009

В зависимости от того, сколько данных в таблицах, вам может потребоваться разместить индексы в столбцах, к которым выполняется соединение. Часто медленная скорость запросов сводится к отсутствию индекса в нужном месте.

Также:

ЛЕВЫЕ СОЕДИНЕНИЯ медленнее, чем ВНУТРЕННИЕ СОЕДИНЕНИЯ (хотя это зависит от того, что именно вы делаете) - можете ли вы выполнить то, что вы ищете, с помощью внутренних объединений?

5 голосов
/ 30 апреля 2009

Сколько данных мы говорим? Возможно, у вас много данных, и когда в конце процесса запроса выполняется условие where, вы объединяете огромные объемы данных перед их фильтрацией.

В этом случае лучше фильтровать данные как можно скорее, поэтому, если вы можете ограничить данные из T1 в первом внутреннем блоке, выберите все другие объединения, которые будут объединены с более ограниченным набором данных.

Select <your fields> from
(
Select * from t1 where t1_id = t1_value
) t1

Inner join t2
on t1.ID = t2.ID
...

если не масс данных; проверьте правильность своих индексов, затем проверьте тип сервера; фрагментация индекса; дисковые очереди и т. д.

5 голосов
/ 30 апреля 2009

Было бы немного полезно, если бы вы могли опубликовать план объяснения запроса.

Но, прежде всего, у вас есть индексы для всех полей, используемых в объединении? что-то вроде CREATE INDEX ix_t2_id on t2 (t2_id, t2_name);

Вместо объединений вы можете сделать что-то вроде

SELECT t1_id, 
    (select t2_name from t2 where t1_id = t2_id), 
    (select t3_name from t3 where t1_id = t3_id), 
    (select t4_name from t4 where t1_id = t4_id), 
    (select t5_name from t5 where t1_id = t5_id), 
    (select t6_name from t6 where t1_id = t6_id), 
    (select t7_name from t7 where t1_id = t7_id), 
    (select t8_name from t8 where t1_id = t8_id), 
    (select t9_name from t9 where t1_id = t9_id) 
FROM t1 

Но при хорошем планировщике запросов это не должно отличаться от объединений.

1 голос
/ 04 мая 2009

Из вашего плана запросов я могу сделать вывод, что таблицы, именуемые s, n и q, не имеют индекса в поле, к которому они присоединяются.

Поскольку в этих таблицах много строк (около 400,000 строк в их декартовом произведении), и MySQL единственный способ сделать JOIN - это использовать NESTED LOOPS, это действительно займет вечность.

Создайте индекс для этих таблиц или определите объединенное поле как PRIMARY KEY.

1 голос
/ 30 апреля 2009

Если вам нужны все строки t1, и вы оставили соединение по первичному ключу (я полагаю, это также кластеризованный индекс) других таблиц, повысить скорость запроса невозможно.

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

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

В зависимости от вашей версии SQL-сервера простое помещение запроса в хранимую процедуру может иметь большое значение. Попробуйте это после того, как вы сначала попробовали другие оптимизации. (Да, я знаю, что есть кэшированные планы выполнения и другие внутренние оптимизации сервера, но из моего практического практического опыта хранимые процедуры могут выполняться быстрее.)

0 голосов
/ 30 апреля 2009

Как я вижу, таблица t1 - это та, которая объединяется со всеми таблицами, вместо того, чтобы помещать их в один запрос с таким количеством объединений, вы можете попробовать объединить разные запросы примерно так:

SELECT  t1_id, t2_name 
FROM    t1 LEFT JOIN t2 ON (t1_id = t2_id)
union 
SELECT  t1_id, t3_name 
FROM    t1 LEFT JOIN t3 ON (t1_id = t3_id)

однако, в этом случае полученный результат будет иметь не 8 столбцов, а только 1 столбец. не уверен, доступен ли вам этот вариант.

Еще одна вещь, которую вы должны использовать в любом решении, которое вы реализуете, - создать соответствующий индекс для всех ваших таблиц. Рекомендуется создавать столбцы индекса для столбца, который чаще всего используется для объединений или оператора where.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...