MySQL подзапрос странно медленно - PullRequest
3 голосов
/ 18 марта 2010

У меня есть запрос на выбор из другого подзапроса выбора. Хотя два запроса выглядят практически одинаково, второй запрос (в этом примере) выполняется намного медленнее:

SELECT
   user.id
  ,user.first_name
  -- user.*
  FROM user
  WHERE
    user.id IN (SELECT ref_id 
                  FROM education 
                 WHERE ref_type='user' 
                   AND education.institute_id='58' 
                   AND education.institute_type='1'
                );

Этот запрос занимает 1.2s Объяснить результаты этого запроса:

 id select_type table   type    possible_keys   key key_len ref rows    Extra
 1  PRIMARY         user   index    first_name  152 141192  Using where; Using index
 2  DEPENDENT SUBQUERY  education   index_subquery  ref_type,ref_id,institute_id,institute_type,ref_type_2  ref_id  4   func    1   Using where

Второй запрос:

SELECT
  -- user.id
  -- user.first_name
  user.*
  FROM user
  WHERE
    user.id IN (SELECT ref_id 
                  FROM education 
                 WHERE ref_type='user' 
                   AND education.institute_id='58' 
                   AND education.institute_type='1'
                );

Требуется 45 секунд для запуска с объяснением:

 id select_type table   type    possible_keys   key key_len ref rows    Extra
 1  PRIMARY user    ALL                 141192  Using where
 2  DEPENDENT SUBQUERY  education   index_subquery  ref_type,ref_id,institute_id,institute_type,ref_type_2  ref_id  4   func    1   Using where

Почему это медленнее, если я запрашиваю только по индексным полям? Почему оба запроса сканируют всю длину пользовательской таблицы? Есть идеи как улучшить?

Спасибо.

Ответы [ 3 ]

5 голосов
/ 18 марта 2010

Я не уверен, почему он выбирает использовать индекс, когда вы выбираете только два столбца, но не когда вы выбираете все столбцы, но лучше выбрать только те столбцы, которые вам нужны. Также может быть лучше попробовать JOIN вместо подзапроса:

SELECT
    user.id
    user.first_name
FROM user
JOIN education 
ON user.id = education.ref_id 
AND education.ref_type='user' 
AND education.institute_id='58' 
AND education.institute_type='1'
4 голосов
/ 18 марта 2010

У меня было несколько случаев, когда замена "WHERE foo in (подзапрос)" на сброс результатов подзапроса во временную таблицу и использование внутреннего соединения серьезно повышала производительность. (Например, 6,5-минутный запрос превращается в запрос за секунду.)

Вот что ... Марк Байерс только что сказал.

3 голосов
/ 18 марта 2010

Вот что я думаю:

Планировщик запросов превратит запрос во внутреннее соединение, что дает базе данных свободу начинать с любой таблицы при фильтрации результата.

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

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

(Извините, если какая-то терминология окрашена в SQL Server, это то, что я регулярно использую.)

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