оптимизировать запрос (2 простых соединения слева) - PullRequest
1 голос
/ 21 апреля 2011
SELECT fcat.id,fcat.title,fcat.description, 
count(DISTINCT ftopic.id) as number_topics, 
count(DISTINCT fpost.id) as number_posts FROM fcat 
LEFT JOIN ftopic ON fcat.id=ftopic.cat_id 
LEFT JOIN fpost ON ftopic.id=fpost.topic_id 
GROUP BY fcat.id
ORDER BY fcat.ord
LIMIT 100;

индекс для ftopic_cat_id, fpost.topic_id, fcat.ord

ОБЪЯСНЕНИЕ:

id      select_type     table   type    possible_keys       key         key_len     ref             rows    Extra
1       SIMPLE          fcat    ALL     PRIMARY             NULL        NULL        NULL            11      Using temporary; Using filesort
1       SIMPLE          ftopic  ref     PRIMARY,cat_id_2    cat_id_2    4           bloki.fcat.id   72   
1       SIMPLE          fpost   ref     topic_id_2          topic_id_2  4           bloki.ftopic.id 245 

fcat - 11 строк, ftopic - 1106 строк, fpost - 363000 строк

Запрос занимает 4,2 сек

ТАБЛИЦЫ:

CREATE TABLE IF NOT EXISTS `fcat` (
  `id` int(11) NOT NULL auto_increment,
  `title` varchar(250) collate utf8_unicode_ci NOT NULL,
  `description` varchar(250) collate utf8_unicode_ci NOT NULL,
  `created` datetime NOT NULL,
  `visible` tinyint(4) NOT NULL default '1',
  `ord` int(11) NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `ord` (`ord`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=12 ;

CREATE TABLE IF NOT EXISTS `ftopic` (
  `id` int(11) NOT NULL auto_increment,
  `cat_id` int(11) NOT NULL,
  `title` varchar(100) collate utf8_unicode_ci NOT NULL,
  `created` datetime NOT NULL,
  `updated` timestamp NOT NULL default CURRENT_TIMESTAMP,
  `lastname` varchar(200) collate utf8_unicode_ci NOT NULL,
  `visible` tinyint(4) NOT NULL default '1',
  `closed` tinyint(4) NOT NULL default '0',
  `views` int(11) NOT NULL default '1',
  PRIMARY KEY  (`id`),
  KEY `cat_id_2` (`cat_id`,`updated`,`visible`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1116 ;

CREATE TABLE IF NOT EXISTS `fpost` (
  `id` int(11) NOT NULL auto_increment,
  `topic_id` int(11) NOT NULL,
  `pet_id` int(11) NOT NULL,
  `content` text collate utf8_unicode_ci NOT NULL,
  `imageName` varchar(300) collate utf8_unicode_ci NOT NULL,
  `created` datetime NOT NULL,
  `reply_id` int(11) NOT NULL,
  `visible` tinyint(4) NOT NULL default '1',
  `md5` varchar(100) collate utf8_unicode_ci NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `md5` (`md5`),
  KEY `topic_id_2` (`topic_id`,`created`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=390971 ;

Спасибо, деревня

Ответы [ 2 ]

0 голосов
/ 21 апреля 2011

Перезапись жирным шрифтом

Этот код функционально не идентичен, но ...

Поскольку вы хотите знать о distinct ftopic.id и fpost.idЯ собираюсь быть смелым и предложить два ВНУТРЕННИХ СОЕДИНЕНИЯ вместо ВЛЕВОГО СОЕДИНЕНИЯ.Тогда, поскольку два идентификатора являются автоинкрементными, они больше не будут повторяться, поэтому вы можете сбросить distinct.

SELECT 
  fcat.id
  , fcat.title
  , fcat.description
  , count(ftopic.id) as number_topics
  , count(fpost.id) as number_posts 
FROM fcat 
INNER JOIN ftopic ON fcat.id = ftopic.cat_id 
INNER JOIN fpost ON ftopic.id = fpost.topic_id 
GROUP BY fcat.id
ORDER BY fcat.ord
LIMIT 100;

Это зависит от ваших данных, если это то, что вы ищете, но я предполагаю, что это будет быстрее.

Хотя все ваши индексы в порядке.

MySQL не использует индексы для небольших размеров выборки!
Обратите внимание, что список explain, который MySQL имеет только 11 строк , следует учитывать для fcat.Этого недостаточно для того, чтобы MySQL действительно начал беспокоиться об индексах, поэтому этого не происходит.
Поскольку переход к индексу для небольшого числа строк замедляет процесс.

MySQL пытается ускорить процесс, поэтому он решает не использовать индекс, это сбивает с толку многих людей, потому что мы так усердно изучаем этот индекс.Малые размеры выборки не дают хорошего объяснения!

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

Распространенные заблуждения относительно force index
Force index не делает не , заставляет MySQL использовать индекс как таковой.
Он намекает MySQL на использование отличного индекса от индекса, который он, естественно, мог бы использовать и это подталкивает MySQL к использованию индекса, устанавливая очень высокую стоимость сканирования таблицы.
(В вашем случае MySQL не при использовании сканирования таблицы, поэтому force index имеетбез эффекта)

MySQL (как и большинство других СУБД на планете) очень сильно хочет использовать индексы, поэтому, если он этого не делает, то потому, что вообще не использовать индекс, быстрее,

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

Советы по улучшению использования индекса

  1. ANALYZE TABLE даст MySQL указание переоценить индексы и обновить распределение ключей (количество элементов). (рассмотрите возможность ежедневного / еженедельного запуска в задании cron)
  2. SHOW INDEX FROM table отобразит распределение ключей.
  3. Фрагменты таблиц и индексов MyISAM с течением времени.Используйте OPTIMIZE TABLE, чтобы фрагментировать таблицы и воссоздать индексы.
  4. FORCE/USE/IGNORE INDEX ограничивает параметры Оптимизатор запросов MySQL должен выполнять ваш запрос.Учитывайте только сложные запросы.
  5. Время эффекта вашего вмешательства с индексами на регулярной основе .Принудительный индекс, который ускоряет ваш запрос сегодня, может замедлить его завтра, потому что базовые данные изменились.
0 голосов
/ 21 апреля 2011

вам нужно создать ключ с fcat.id, fcat.ord

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