Индексирование MySQL в операторе "или" - PullRequest
2 голосов
/ 01 июля 2011

У меня есть 3 таблицы, к которым мне нужно присоединиться, они прекрасно объединяются с использованием индексов.Однако мы переходим от использования одного унаследованного поля в качестве идентификатора к другому в другой таблице.LEGACYID - это прежнее поле, а NEWID - новое поле.Оба поля являются varchars.Оба поля индексируются исключительно с помощью индекса btree, обе таблицы - MyISAM.

SELECT Username  
  FROM CUST C use index(primary,NEWID)
  JOIN TBLSHP S ON S.CUSID = C.CUSID
  JOIN TBLQ Q ON Q.SHPID = S.SHPID
 WHERE C.LEGACYID = '692041' 
    OR Q.NEWID = '692041'

Этот запрос занимает 5,147 секунды, что на 5 секунд больше, чем я ожидаю.

При выполнении запроса EXPLAIN EXTENDEDтип индекса для NEWID - ВСЕ, т.е. полное сканирование таблицы, возможные ключи (первичный, NEWID) и ключ (нулевой).Если я удалю LEGACYID из оператора Or, объяснение говорит, что теперь будет использоваться ключ (NEWID).Если я удаляю NEWID из оператора OR, изменения происходят следующим образом:

  • тип таблицы объединяется для изменения (S, C) с типа ref на eq_ref
  • key_len изменяется с 4до 5 (на обоих)
  • дополнительные изменения с пустого на «Использование где».При удалении одного из операторов из оператора OR запрос выполняется с ожидаемой скоростью.

Таблица Q содержит 183 тыс. Записей;C: 115K;S: 169K.Последний пункт.если я переместу размещение запроса:

   SELECT Username  
     FROM CUST C use index(primary,NEWID)
     JOIN TBLSHP  S ON S.CUSID = C.CUSID
LEFT JOIN TBLQ Q ON Q.SHPID = S.SHPID 
                AND Q.NEWID = '692041'
    WHERE C.LEGACYID = '692041' 

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

Я хотел уточнить, что мне действительно не нужен запрос, который работает решением.Благодаря Пони ниже, который уже предоставил один.Мне нужно знать, сталкивался ли кто-либо еще с этой проблемой и может ли объяснить, почему это происходит, и что я могу сделать, чтобы это простое или утверждение использовало оба индекса.

1 Ответ

1 голос
/ 01 июля 2011

Если вы знаете, что дубликатов не будет, измените UNION на UNION ALL (UNION ALL быстрее, поскольку не удаляет дубликаты). В противном случае используйте:

SELECT Username  
  FROM CUST C use index(primary,NEWID)
  JOIN TBLSHP S ON S.CUSID = C.CUSID
  JOIN TBLQ Q ON Q.SHPID = S.SHPID
 WHERE C.LEGACYID = '692041' 
UNION
SELECT Username  
  FROM CUST C use index(primary,NEWID)
  JOIN TBLSHP S ON S.CUSID = C.CUSID
  JOIN TBLQ Q ON Q.SHPID = S.SHPID
 WHERE Q.NEWID = '692041'

OR s, как известно, плохие исполнители, потому что это расщепляет путь выполнения. UNION смягчает это расщепление, и объединяет два набора результатов. Тем не менее, IN предпочтительнее OR с, потому что, хотя логически то же самое, выполнение IN, как правило, более оптимизировано.

UNION не всегда ответ

Изучите множество вариантов, сравнивая вывод EXPLAIN PLAN, прежде чем определять решение. Недавно я встретил пару, которые лучше справляются с использованием курсора, чем один запрос с использованием эзотерических функций.

Также убедитесь, что столбцы внешнего ключа (то, что вы используете в предложении ON при JOINing) проиндексированы. MySQL начал (v5.5 +?), Чтобы автоматически делать это, когда накладывается ограничение внешнего ключа, но это только для таблиц InnoDB.

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