Производительность MySQL с использованием предиката IN - PullRequest
2 голосов
/ 10 октября 2009

Если я запускаю следующие запросы, каждый возвращается быстро (0,01 сек) и дает мне желаемый результат.

SELECT tagId FROM tag WHERE name='programming'

SELECT COUNT(DISTINCT workcode) FROM worktag WHERE tagId=123 OR tagId=124

(предположим, что два номера tagId были результатами первого запроса)

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

SELECT COUNT(DISTINCT workcode) FROM worktag WHERE tagId IN (SELECT tagId FROM tag WHERE name='programming')

Однако этот запрос завершается примерно за 1 мин 20 с. У меня есть индексы на worktag.workcode, worktag.tagId, tag.tagId и tag.name.

Если я запускаю DESCRIBE для запросов, первые два используют индексы, а второй использует индекс для подзапроса (в таблице tag), но не использует индексы в таблице worktag.

Кто-нибудь знает, почему это может быть?

ПРИМЕЧАНИЕ. В таблице worktag содержится более 18 миллионов записей.

Ответы [ 6 ]

2 голосов
/ 10 октября 2009

Почему вы не используете объединение вместо подзапроса?

SELECT COUNT(DISTINCT workcode)
FROM worktag
LEFT JOIN tag
  ON worktag.tagId = tag.tagID
WHERE tag.name = 'programming'

P.S .: Кажется, что сообщается как ошибка .

1 голос
/ 10 октября 2009

MySQL обычно не так хорошо работает с подзапросами, даже с независимыми. Постеры, которые обсуждали объединения, верны - если у вас есть выбор, используйте объединение. Если вы не можете легко использовать объединение (например, foo.x in (выберите y из бара, где y = xxx limit 10)), вам лучше запустить ограничение во временную таблицу IN MEMORY и использовать объединение на нем .

Если вы часто используете MySQL, используйте EXPLAIN, и вы увидите, как он использует ваши индексы и тому подобное.

1 голос
/ 10 октября 2009
SELECT COUNT(DISTINCT workcode) 
FROM worktag 
inner join tag on worktag.tagid = tag.tagid
WHERE tag.name='programming'
1 голос
/ 10 октября 2009

Администратор базы данных недавно сказал мне, что синтаксис WHERE x IN ( ... ) - это боль для базы данных. Объединение почти всегда лучше:

SELECT COUNT(DISTINCT wt.workcode) 
  FROM worktag wt, tag t 
 WHERE wt.tagId = t.tagId 
   AND t.name='programming'
0 голосов
/ 10 октября 2009

Полагаю, оптимизатор ошибается. Замена запроса внутренним объединением может помочь.

0 голосов
/ 10 октября 2009

Вы пробовали:

SELECT COUNT(DISTINCT workcode) FROM worktag WHERE tagId IN (123, 124)

Я не эксперт по MySQL, но мне кажется, что вы можете заметить существенную ошибку оптимизатора запросов.

С другой стороны, хорошо для MySQL, что он оптимизирует ИЛИ во втором операторе. Я знаю базы данных, которые будут успешно оптимизировать IN (), но не версию OR того же логического запроса.

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