2014-01-15 1 views
5

Рассмотрим следующий запрос:Использование индекса в LEFT JOIN с ИЛИ условие

SELECT * 
FROM table1 
LEFT JOIN table2 ON 
    table2.some_primary_key = table1.some_primary_key 
LEFT JOIN table3 ON 
    table3.some_primary_key = table1.some_primary_key OR -- this is the issue 
    table3.column_with_index = table2.column_with_index 

в то время как я проверяю EXPLAIN он мне показывает индекс не используется для table3 присоединения (однако показатели приведены в «possible_keys»). Тип: «ВСЕ». Согласно manual:

типа «ALL» Регистрация: полное сканирование таблицы выполняется для каждой комбинации строк из предыдущих таблиц .

Запрос ужасно медленный.

Но когда я удалить одно из условий, так что будет:

LEFT JOIN table3 ON 
    table3.some_primary_key = table1.some_primary_key 

ИЛИ

LEFT JOIN table3 ON 
    table3.column_with_index = table2.column_with_index 

Mysql использует индексы правильно. В EXPLAIN показатели результата показаны в столбце «ключи», тип - «ref». Запросы быстро растут.

Что делать, чтобы mysql использовал мои индексы при использовании OR в заявлении о соединении?

Я пробовал LEFT JOIN table3 FORCE INDEX(PRIMARY, ind_column), но не удался.

+0

Я думаю, что многие базы данных имеют проблема с использованием индексов с 'OR'. – Barmar

+0

Сколько у вас свободы в проекционной части вашего запроса? –

+0

Я хочу загрузить все данные в один большой запрос, извините, я не могу быть более конкретным. До сих пор мне приходит в голову, что две таблицы3 соединяются (table3a, table3b) и 'CASE' в' SELECT' (если table3a primary not null, используйте поля table3a, если table3b primary not null использует поля table3b). Может быть, я могу пойти на другие обходные пути, но я задал этот вопрос, потому что мне любопытно, есть ли какое-либо действительно хорошее решение для этой проблемы. – Peter

ответ

1

Я могу предложить вам использовать CASE statement,

Here аналогичный вопрос вы можете взять и расширить свои нужды:

Надеется, что это помогает

+1

Да, я пойду с этим. В моем случае 2xJOIN с оператором CASE будет дешевле, чем UNION – Peter

1

Разделите запрос на два запроса, каждый из которых использует другое условие от OR, а затем объедините их с помощью UNION.

SELECT * 
FROM table1 
LEFT JOIN table2 ON 
    table2.some_primary_key = table1.some_primary_key 
LEFT JOIN table3 ON 
    table3.some_primary_key = table1.some_primary_key 

UNION 

SELECT * 
FROM table1 
LEFT JOIN table2 ON 
    table2.some_primary_key = table1.some_primary_key 
LEFT JOIN table3 ON 
    table3.column_with_index = table2.column_with_index 
+0

Действительно ли это единственный способ ? Мой запрос намного сложнее моего примера ... – Peter

+0

Согласовано, но недостатком является то, что операция соединения таблицы2 происходит дважды, а 'UNION' стоит дорого. –

+0

К сожалению, я не думаю, что MySQL может оптимизировать «ИЛИ». Я думаю, что он может использовать только один индекс для таблицы для любого конкретного соединения, и для этого потребуется использовать другой индекс для каждого условия в 'OR'. – Barmar

Смежные вопросы