Нужна помощь в расшифровке вывода MYSQL EXPLAIN для сложного соединения - PullRequest
0 голосов
/ 21 октября 2011

На главной странице моего сайта сложный запрос, который выглядит следующим образом:

SELECT karmalog.*, image.title as img_title, image.date_uploaded, imagefile.file_name as img_filename, imagefile.width as img_width, imagefile.height as img_height, imagefile.transferred as img_transferred, u1.uname as usr_name1, u2.uname as usr_name2, u1.avat_url as usr_avaturl1, u2.avat_url as usr_avaturl2, class.title as class_title,forum.id as f_id, forum.name as f_name, forum.icon, forumtopic.id as ft_id, forumtopic.subject
FROM karmalog 
LEFT JOIN image on karmalog.event_type = 'image' and karmalog.object_id = image.id 
LEFT JOIN imagefile on karmalog.object_id = imagefile.image_id and imagefile.type = 'smallthumb'
LEFT JOIN class on karmalog.event_type = 'class' and karmalog.object_id = class.num
LEFT JOIN user as u1 on karmalog.user_id = u1.id
LEFT JOIN user as u2 on karmalog.user_sec_id = u2.id
LEFT JOIN forumtopic on karmalog.object_id = forumtopic.id and karmalog.event IN ('FORUM_REPLY','FORUM_CREATE')
LEFT JOIN forum on forumtopic.forum_id = forum.id
WHERE karmalog.event IN ('EDIT_PROFILE','FAV_IMG_ADD','FOLLOW','COM_POST','IMG_UPLOAD','IMG_VOTE','LIST_VOTE','JOIN','CLASS_UP','CLASS_DOWN','LIST_CREATE','FORUM_REPLY','FORUM_CREATE','FORUM_SUBSCRIBE')
  AND karmalog.delete=0
ORDER BY karmalog.date_created DESC, karmalog.id DESC 
LIMIT 0,13 

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

В настоящее время выполнение этого запроса занимает 2 секунды, но со временем он будет работать медленнее по мере увеличения количества записей. Поэтому я ищу, чтобы оптимизировать это. Вот вывод объяснения MYSQL:

enter image description here

Мое понимание EXPLAIN слишком ограничено, чтобы понять это. Я бы предпочел оставить этот запрос как есть (вместо его денормализации), но при этом улучшить его производительность, используя соответствующие индексы или другие быстрые выигрыши. Основываясь на этом выводе объяснения, видите ли вы что-нибудь, с чем я могу продолжить?

Редактировать: в соответствии с настоящим требованием определение таблицы karmalog:

CREATE TABLE `karmalog` (
  `id` int(11) NOT NULL auto_increment,
  `guid` char(36) default NULL,
  `user_id` int(11) default NULL,
  `user_sec_id` int(11) default NULL,
  `event` enum('EDIT_PROFILE','EDIT_AVATAR','EDIT_EMAIL','EDIT_PASSWORD','FAV_IMG_ADD','FAV_IMG_ADDED','FAV_IMG_REMOVE','FAV_IMG_REMOVED','FOLLOW','FOLLOWED','UNFOLLOW','UNFOLLOWED','COM_POSTED','COM_POST','COM_VOTE','COM_VOTED','IMG_VOTED','IMG_UPLOAD','LIST_CREATE','LIST_DELETE','LIST_ADMINDELETE','LIST_VOTE','LIST_VOTED','IMG_UPD','IMG_RESTORE','IMG_UPD_LIC','IMG_UPD_MOD','IMG_UPD_MODERATED','IMG_VOTE','IMG_VOTED','TAG_FAV_ADD','CLASS_DOWN','CLASS_UP','IMG_DELETE','IMG_ADMINDELETE','IMG_ADMINDELETEFAV','SET_PASSWORD','IMG_RESTORED','IMG_VIEW','FORUM_CREATE','FORUM_DELETE','FORUM_ADMINDELETE','FORUM_REPLY','FORUM_DELETEREPLY','FORUM_ADMINDELETEREPLY','FORUM_SUBSCRIBE','FORUM_UNSUBSCRIBE','TAG_INFO_EDITED','JOIN') NOT NULL,
  `event_type` enum('follow','tag','image','class','list','forum','user') NOT NULL,
  `active` bit(1) NOT NULL,
  `delete` bit(1) NOT NULL default '\0',
  `object_id` int(11) default NULL,
  `object_cache` varchar(1024) default NULL,
  `karma_delta` int(11) NOT NULL,
  `gold_delta` int(11) NOT NULL,
  `newkarma` int(11) NOT NULL,
  `newgold` int(11) NOT NULL,
  `mail_processed` bit(1) NOT NULL default '\0',
  `date_created` timestamp NOT NULL default '0000-00-00 00:00:00',
  PRIMARY KEY  (`id`),
  KEY `user_id` (`user_id`),
  KEY `user_sec_id` (`user_sec_id`),
  KEY `image_id` (`object_id`),
  CONSTRAINT `user_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE SET NULL,
  CONSTRAINT `user_sec_id` FOREIGN KEY (`user_sec_id`) REFERENCES `user` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Ответы [ 3 ]

3 голосов
/ 21 октября 2011
  • Во-первых, вам, вероятно, не хватает составного индекса на (event_type, object_id).Во втором чтении не обращайте на это внимания.Вам может понадобиться такой индекс для других запросов, но не для этого (из-за ORDER BY ... LIMIT).

  • Во-вторых, у вас нет индекса на date_created, и выORDER BY этот столбец.Добавить индекс по этому.Принимая во внимание условия WHERE, лучшим индексом может быть (delete, date_created), (event, date_created) или (вероятно, лучший): (event, delete, date_created).

  • В-третьих, попробуйтепереписать его следующим образом:

сначала LIMIT, затем JOIN (исправлено):

SELECT karmalog.*, image.title as img_title, image.date_uploaded, imagefile.file_name as img_filename, imagefile.width as img_width, imagefile.height as img_height, imagefile.transferred as img_transferred, u1.uname as usr_name1, u2.uname as usr_name2, u1.avat_url as usr_avaturl1, u2.avat_url as usr_avaturl2, class.title as class_title,forum.id as f_id, forum.name as f_name, forum.icon, forumtopic.id as ft_id, forumtopic.subject
FROM 
    ( SELECT *
      FROM karmalog
      WHERE karmalog.event IN ('EDIT_PROFILE','FAV_IMG_ADD','FOLLOW','COM_POST','IMG_UPLOAD','IMG_VOTE','LIST_VOTE','JOIN','CLASS_UP','CLASS_DOWN','LIST_CREATE','FORUM_REPLY','FORUM_CREATE','FORUM_SUBSCRIBE')
        AND karmalog.delete=0
      ORDER BY karmalog.date_created DESC, karmalog.id DESC 
      LIMIT 0,13  
    ) AS karmalog 
LEFT JOIN image on karmalog.event_type = 'image' and karmalog.object_id = image.id 
LEFT JOIN imagefile on karmalog.object_id = imagefile.image_id and imagefile.type = 'smallthumb'
LEFT JOIN class on karmalog.event_type = 'class' and karmalog.object_id = class.num
LEFT JOIN user as u1 on karmalog.user_id = u1.id
LEFT JOIN user as u2 on karmalog.user_sec_id = u2.id
LEFT JOIN forumtopic on karmalog.object_id = forumtopic.id and karmalog.event IN ('FORUM_REPLY','FORUM_CREATE')
LEFT JOIN forum on forumtopic.forum_id = forum.id
ORDER BY karmalog.date_created DESC, karmalog.id DESC 
2 голосов
/ 21 октября 2011

Важными частями объяснения являются: possible keys, keys и rows.

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

  • низкая мощность ключа;
  • использование функций;

Сосредоточьте свои усилия на столе с наибольшим количеством строк. т.е. karmalog.

Помните, что MySQL может использовать только один индекс для выбора для таблицы.
Все объединения являются левыми, поэтому они не ограничивают количество строк в индексах karmalog. Здесь вам не помогут.
Если смотреть на часть where, то deleted имеет низкую мощность (только 2 значения, 90% из которых будут =0). Так что только поля event + date_created имеют право на индекс, поместите индекс на:

ALTER TABLE karmalog ADD INDEX date_event (event, date_created);
1 голос
/ 21 октября 2011

Попробуйте поместить индекс в таблицу определенно событие karmalog (возможно delete и object_id), так как это ускорит его и даст ключ для первого соединения.

Второй взгляд на эту таблицу и рисунокесли бы вы могли сделать это с помощью какого-то соединения, чтобы сделать его легче в будущем.Но это, вероятно, будет означать изменение вашего БД

karmalog.event IN ('EDIT_PROFILE','FAV_IMG_ADD','FOLLOW','COM_POST','IMG_UPLOAD','IMG_VOTE','LIST_VOTE','JOIN','CLASS_UP','CLASS_DOWN','LIST_CREATE','FORUM_REPLY','FORUM_CREATE','FORUM_SUBSCRIBE')
...