2012-06-25 2 views
0

Мне было поручено поддерживать приложение для клиента, который очень медленный. Я включил MySQL slow_query_log и нашел несколько запросов, которые кажутся виновными. Я немного смущен в отношении того, что делает этот запрос, но любые рекомендации о том, как я мог бы переписать это, были бы полезны.Really Slow Выполнение MySQL Query

SELECT 
    table_a.id AS table_a_id_1, 
    table_a2.id AS table_a_id_2 
FROM 
    table_a, 
    table_b 
LEFT JOIN 
    table_a AS table_a2 
ON 
    table_a.value = table_a2.value 
WHERE 
    table_a.value_id = 112 AND 
    table_a2.value_id = 113 AND 
    table_a.status != table_a2.status AND 
    table_a.id = table_b.id; 

Для меня это выглядит как запрос выбирает одни и те же данные дважды из одной таблицы, а затем делать какие-то сравнения с выбранными данными, а также для выполнения объединения с TABLE_B, а также. Вот журнал из MySQL, ссылающийся на выполнение этого запроса.

Query_time: 160.854398 
Lock_time: 0.000139 
Rows_sent: 12 
Rows_examined: 10339025 

Любой совет, который вы могли бы предоставить, был бы полезен!

+0

Я даже не думаю, что запрос действителен ... Вы уверены, что он работает правильно? Вы внесли какие-либо изменения в запрос перед его публикацией? –

+0

Я тоже не думал, что это действительно так, это выглядит странно для меня. Однако он работает без ошибок и возвращает строки. Единственные изменения, которые я внес в запрос, заключались в замене имен таблиц на таблицы_a и table_b ... и т. Д. Я проверю и посмотрю, смогу ли я опубликовать фактический полный запрос, если вы думаете, что это поможет. Это еще более запутанно ... LOL! –

+1

Это очень плохая идея объединить эксплицитные и неявные объединения (и использование неявных объединений вообще - это антиспам SQL). Простое исправление для использования explict joins wil probaly help, тогда вам нужно исправить части вашего запроса, которые являются плохими ошибками. См. Мои комментарии в ответе @ GordonLinoff. – HLGEM

ответ

3

Вполне возможно, что план запроса создает перекрестное соединение, как указано в предложении WHERE:

SELECT table_a.id AS table_a_id_1, 
     table_a2.id AS table_a_id_2 
FROM table_a join 
    table_b 
    on table_a.id = table_b.id LEFT JOIN 
    table_a AS table_a2 
    ON table_a.value = table_a2.value 
WHERE table_a.value_id = 112 AND 
     table_a2.value_id = 113 AND 
     table_a.status != table_a2.status 

Это также наводит на мысль, что индексы на table_a.id и table_a.value и table_b.id может помочь много.

Теперь, возможно, вы сможете упростить этот запрос. Например, похоже, что в таблице_a появляются пары 112, 113, где статусы различны. Я действительно не вижу, где используется table_b, если только для некоторого критерия фильтрации. Вы можете получить этот список более эффективно, выполнив что-то вроде:

SELECT table_a.id AS table_a_id_1, 
     table_a2.id AS table_a_id_2 
FROM (select ta.* from table_a ta where ta.value_id = 112) ta join 
    (select ta.* from table_a ta where ta.value_id = 113) ta2 
    ON ta.value = ta2.value and 
     ta.status != ta2.status 
+0

table_a2.value_id = 113 должно быть в условии where или вы преобразовываете левое соединение во внутреннее соединение. и table_a.status! = table_a2.status требует объединения, чтобы избежать сравнения нулевого значения со значением. – HLGEM

+0

Я делаю здесь соединение и в основном конвертирую левое соединение в регулярное соединение. Я думаю, что левое объединение избыточно, потому что предложение where в исходном запросе гарантирует, что значения NULL на стороне table_a2 будут отброшены. Тем не менее, я никогда не думал о левом объединении, где условие «on» не ссылается на первую таблицу, поэтому я не уверен, что SQL указывает (или что делает mysql) в этом случае. Возможно, он соединяет крест на первых двух таблицах, и это остается присоединенным к третьей таблице? –