Вложенная производительность "select ... in" работает медленно - как это исправить? - PullRequest
1 голос
/ 08 декабря 2011

Здесь у меня есть простой запрос на соединение.Если первые два запроса дают результаты, весь запрос может быть выполнен за 0,3 секунды, но если первые 2 выбора не извлекают никакого результата, весь запрос будет стоить более полминуты.Что вызывает эту разницу?Как решить эту проблему и улучшить производительность?

SELECT * FROM music WHERE id IN
(
    SELECT id FROM music_tag_map WHERE tag_id IN 
    (
        SELECT id FROM tag WHERE content ='xxx'
    )
) 
LIMIT 10

Вот структура таблицы:

CREATE TABLE `tag` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `content` varchar(20) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `index2` (`content`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `music` (
  `id` int(7) NOT NULL AUTO_INCREMENT,
  `name` varchar(500) NOT NULL,
  `othername` varchar(200) DEFAULT NULL,
  `player` varchar(3000) DEFAULT NULL,
  `genre` varchar(100) DEFAULT NULL,
  `sounds` text,
  `create_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `player` (`player`(255)),
  KEY `name` (`othername`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `music_tag_map` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `music_id` int(7) NOT NULL,
  `tag_id` int(7) NOT NULL,
  `times` int(11) DEFAULT '1',
  PRIMARY KEY (`id`),
  KEY `music_id` (`music_id`),
  KEY `tag_id` (`tag_id`),
  CONSTRAINT `music_tag_map_ibfk_1` FOREIGN KEY (`id`) REFERENCES `music` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `music_tag_map_ibfk_2` FOREIGN KEY (`tag_id`) REFERENCES `tag` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

1 Ответ

2 голосов
/ 08 декабря 2011

В этом запросе нет соединений; Есть два суб-выбора.

Объединенный запрос будет:

SELECT * 
  FROM music 
    JOIN music_tag_map ON music.id=music_tag_map.id
    JOIN tag ON music_tag_map.tag_id=tag.id
  WHERE tag.content = ?
  LIMIT 10;

EXPLAIN, примененный к каждому, покажет вам, почему объединение работает лучше, чем суб-выбор: суб-выбор будет сканировать всю таблицу music (основной запрос), в то время как оптимизатор может выбрать порядок таблицы для сканирования объединений, что позволяет MySQL использовать индексы для получения только необходимых строк из всех таблиц.

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