Подтвердить что ты не робот

Sql query объединяет несколько таблиц - слишком медленно (8 таблиц)

Я пытаюсь объединить 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)

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

заблаговременно

4b9b3361

Ответ 1

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

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

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

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

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

Ответ 2

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

также:

LEFT JOINs медленнее, чем INNER JOIN (хотя это зависит от того, что вы делаете в точности) - можете ли вы выполнить то, что вы ищете, с внутренними соединениями?

Ответ 3

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

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

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

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

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

Ответ 4

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

Но, во-первых, у вас есть индексы во всех полях, используемых в соединении? что-то вроде 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 

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

Ответ 5

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

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

Ответ 6

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

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

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

Ответ 7

Как я вижу, таблица 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.

Ответ 8

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