Действительно ли сортировка InnoDB ЭТО медленная? - PullRequest
3 голосов
/ 15 сентября 2009

Все мои таблицы были в myISAM, но блокировка на уровне таблиц начинала меня убивать, когда у меня были длинные задания обновлений. Я преобразовал свои первичные таблицы в InnoDB, и теперь многие из моих запросов занимают более 1 минуты, чтобы выполнить их почти мгновенно на myISAM. Они обычно застряли в шаге Sorting result. Я сделал что-то не так?

Например:

SELECT * FROM `metaward_achiever` 
 INNER JOIN `metaward_alias` ON (`metaward_achiever`.`alias_id` = `metaward_alias`.`id`) 
 WHERE `metaward_achiever`.`award_id` = 1507  
 ORDER BY `metaward_achiever`.`modified` DESC 
 LIMIT 100  

Занимает около 90 секунд. Вот описание:

+----+-------------+-------------------+--------+-------------------------------------------------------+----------------------------+---------+---------------------------------+-------+-----------------------------+
| id | select_type | table             | type   | possible_keys                                         | key                        | key_len | ref                             | rows  | Extra                       |
+----+-------------+-------------------+--------+-------------------------------------------------------+----------------------------+---------+---------------------------------+-------+-----------------------------+
|  1 | SIMPLE      | metaward_achiever | ref    | metaward_achiever_award_id,metaward_achiever_alias_id | metaward_achiever_award_id | 4       | const                           | 66424 | Using where; Using filesort | 
|  1 | SIMPLE      | metaward_alias    | eq_ref | PRIMARY                                               | PRIMARY                    | 4       | paul.metaward_achiever.alias_id |     1 |                             | 
+----+-------------+-------------------+--------+-------------------------------------------------------+----------------------------+---------+---------------------------------+-------+-----------------------------+

Кажется, что теперь тонны моих запросов застряли в шаге "Результат сортировки":

mysql> show processlist;
+--------+------+-----------+------+---------+------+----------------+------------------------------------------------------------------------------------------------------+
| Id     | User | Host      | db   | Command | Time | State          | Info                                                                                                 |
+--------+------+-----------+------+---------+------+----------------+------------------------------------------------------------------------------------------------------+
| 460568 | paul | localhost | paul | Query   |    0 | NULL           | show processlist                                                                                     | 
| 460638 | paul | localhost | paul | Query   |    0 | Sorting result | SELECT `metaward_achiever`.`id`, `metaward_achiever`.`modified`, `metaward_achiever`.`created`, `met | 
| 460710 | paul | localhost | paul | Query   |   79 | Sending data   | SELECT `metaward_achiever`.`id`, `metaward_achiever`.`modified`, `metaward_achiever`.`created`, `met | 
| 460722 | paul | localhost | paul | Query   |   49 | Updating       | UPDATE `metaward_alias` SET `modified` = '2009-09-15 12:43:50', `created` = '2009-08-24 11:55:24', ` | 
| 460732 | paul | localhost | paul | Query   |   25 | Sorting result | SELECT `metaward_achiever`.`id`, `metaward_achiever`.`modified`, `metaward_achiever`.`created`, `met | 
+--------+------+-----------+------+---------+------+----------------+------------------------------------------------------------------------------------------------------+
5 rows in set (0.00 sec)

Что-нибудь, почему это простое обновление зависло на 49 секунд?

Если это поможет, вот схемы:

| metaward_alias | CREATE TABLE `metaward_alias` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `modified` datetime NOT NULL,
  `created` datetime NOT NULL,
  `string_id` varchar(255) DEFAULT NULL,
  `shortname` varchar(100) NOT NULL,
  `remote_image` varchar(500) DEFAULT NULL,
  `image` varchar(100) NOT NULL,
  `user_id` int(11) DEFAULT NULL,
  `type_id` int(11) NOT NULL,
  `md5` varchar(32) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `string_id` (`string_id`),
  KEY `metaward_alias_user_id` (`user_id`),
  KEY `metaward_alias_type_id` (`type_id`)
) ENGINE=InnoDB AUTO_INCREMENT=858381 DEFAULT CHARSET=utf8 | 

| metaward_award | CREATE TABLE `metaward_award` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `modified` datetime NOT NULL,
  `created` datetime NOT NULL,
  `string_id` varchar(20) NOT NULL,
  `owner_id` int(11) NOT NULL,
  `name` varchar(100) NOT NULL,
  `description` longtext NOT NULL,
  `owner_points` int(11) NOT NULL,
  `url` varchar(500) NOT NULL,
  `remote_image` varchar(500) DEFAULT NULL,
  `image` varchar(100) NOT NULL,
  `parent_award_id` int(11) DEFAULT NULL,
  `slug` varchar(110) NOT NULL,
  `true_points` double DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `string_id` (`string_id`),
  KEY `metaward_award_owner_id` (`owner_id`),
  KEY `metaward_award_parent_award_id` (`parent_award_id`),
  KEY `metaward_award_slug` (`slug`),
  KEY `metaward_award_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=122176 DEFAULT CHARSET=utf8 | 

| metaward_achiever | CREATE TABLE `metaward_achiever` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `modified` datetime NOT NULL,
  `created` datetime NOT NULL,
  `award_id` int(11) NOT NULL,
  `alias_id` int(11) NOT NULL,
  `count` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `metaward_achiever_award_id` (`award_id`),
  KEY `metaward_achiever_alias_id` (`alias_id`)
) ENGINE=InnoDB AUTO_INCREMENT=77175366 DEFAULT CHARSET=utf8 | 

И это в моем my.cnf

innodb_file_per_table
innodb_buffer_pool_size = 2048M
innodb_additional_mem_pool_size = 16M
innodb_flush_method=O_DIRECT

Ответы [ 6 ]

13 голосов
/ 15 сентября 2009

Как написано в Стоит ли переходить с MyISAM на Innodb? (что довольно недавно):

Innodb нуждается в настройке В заключение, о миграции MyISAM на Innodb, я должен упомянуть о настройке Innodb. Innodb нуждается в настройке. В самом деле. MyISAM для многих приложений может хорошо работать со значениями по умолчанию. Я видел сотни баз данных GB, запущенных с MyISAM с настройками по умолчанию, и это работало разумно. Innodb нужны ресурсы, и он не будет хорошо работать со значениями по умолчанию. Настройка MyISAM на значения по умолчанию редко дает выигрыш более чем в 2-3 раза, в то время как для таблиц Innodb он может достигать 10-50 раз, в частности для интенсивной записи. Проверьте здесь для деталей.

Итак, о настройках MySQL Innodb автор написал в Основы оптимизации производительности Innodb :

Наиболее важные из них:

innodb_buffer_pool_size 70-80% память - безопасная ставка. Я установил его на 12G на коробке 16 ГБ.

ОБНОВЛЕНИЕ : Если вы ищете больше подробности, ознакомьтесь с подробным руководством по настройка пула буферов innodb

innodb_log_file_size - Это зависит от ваша скорость восстановления нужна, но 256M кажется, хороший баланс между разумное время восстановления и хорошее производительность

innodb_log_buffer_size = 4M 4M хорошо в большинстве случаев, если вы не трубите большие капли в Innodb в этом случае увеличить его немного.

innodb_flush_log_at_trx_commit = 2 Если вы не беспокоитесь о ACID и можете потерять транзакции за последнюю секунду или две в случае полного сбоя ОС, чем установить это значение. Это может существенно повлиять на множество коротких транзакций записи.

innodb_thread_concurrency = 8 Даже с текущими исправлениями масштабируемости Innodb помогает ограниченный параллелизм. Фактическое число может быть больше или меньше в зависимости от вашего приложения и по умолчанию, которое составляет 8 - приличное начало

innodb_flush_method = O_DIRECT Избегайте двойной буферизации и уменьшайте давление подкачки, в большинстве случаев этот параметр повышает производительность. Однако будьте осторожны, если у вас нет резервной копии RAID-кэша от батареи, так как при записи может возникнуть проблема с вводом-выводом.

innodb_file_per_table - Если у вас не слишком много таблиц, используйте эту опцию, поэтому у вас не будет неконтролируемого увеличения основного табличного пространства innodb, которое вы не сможете восстановить. Эта опция была добавлена ​​в MySQL 4.1 и теперь достаточно стабильна для использования.

Также проверьте, может ли ваше приложение работать в режиме READ-COMMITED, если это так, - установите его по умолчанию как изоляция транзакции = READ-COMMITTED. Эта опция имеет некоторые преимущества в производительности, особенно в блокировке в 5.0 и даже больше в MySQL 5.1 и репликации на уровне строк.

Просто для справки: люди, стоящие за mysqlperformanceblog.com, провели сравнительный тест, сравнивая Falcon, MyISAM и InnoDB. Предполагалось, что бенчмарк должен был подсвечивать Falcon, за исключением того, что победил InnoDB, превзойдя Falcon и MyISAM по количеству запросов в секунду почти для каждого теста: InnoDB против MyISAM против Falcon - часть 1 . 1059 *

4 голосов
/ 15 сентября 2009

Это большой набор результатов (66 424 строки), который MySQL должен сортировать вручную. Попробуйте добавить индекс в metaward_achiever.modified.

В MySQL 4.x существует ограничение, которое позволяет MySQL использовать только один индекс на таблицу. Поскольку он использует индекс для столбца metaward_achiever.award_id для выбора WHERE, он также не может использовать индекс для metaward_achiever.modified для сортировки. Я надеюсь, что вы используете MySQL 5.x, который, возможно, улучшил это.

Вы можете убедиться в этом, объяснив этот упрощенный запрос:

SELECT * FROM `metaward_achiever` 
 WHERE `metaward_achiever`.`award_id` = 1507  
 ORDER BY `metaward_achiever`.`modified` DESC 
 LIMIT 100

Если вы можете получить это, используя индексы для выбора и сортировки WHERE, то все готово.

Вы также можете создать составной индекс с metaward_achiever.award_id и metaward_achiever. Если MySQL не использует его, то вы можете намекнуть на это или удалить тот, который указан просто на award_id.

В качестве альтернативы, если вы можете избавиться от metaward_achiever.id и сделать metaward_achiever.award_id своим первичным ключом и добавить ключ в metaward_achiever.modified или, что еще лучше, сделать metaward_achiever.award_id в сочетании с metaward.modified вашим первичным ключом, тогда вы ' будет действительно хорошо.

Вы можете попытаться оптимизировать сортировку файлов, изменив настройки. К сожалению, у меня нет опыта в этом, так как наш администратор баз данных обрабатывает конфигурацию, но вы можете проверить этот отличный блог: http://www.mysqlperformanceblog.com/

Вот статья о файловой сортировке, в частности: http://s.petrunia.net/blog/?p=24

3 голосов
/ 15 сентября 2009

Полагаю, вы, вероятно, не настроили параметры InnoDB сверх значений по умолчанию. Для настройки параметров InnoDB вам нужно быстро зайти в Google.

Тот, который вызвал у меня самые заметные проблемы с производительностью из коробки, был innodb_buffer_pool_size. Это должно быть установлено на 50-80% памяти вашей машины. По умолчанию это часто всего несколько МБ. Поверните его в сторону вверх, и вы увидите заметное увеличение производительности.

Также взгляните на innodb_additional_mem_pool_size.

Начните здесь , но вы также можете найти "настройку производительности innodb".

2 голосов
/ 15 сентября 2009

Оптимизатор запросов MySQL не очень хорош из моей памяти. Попробуйте отменить выбор вместо прямого соединения.

SELECT * FROM (SELECT * FROM `metaward_achiever` 
               WHERE `metaward_achiever`.`award_id` = 1507) a
INNER JOIN `metaward_alias` ON (a.`alias_id` = `metaward_alias`.`id`) 
ORDER BY a.`modified` DESC 
LIMIT 100

Или что-то в этом роде (непроверенный синтаксис выше).

1 голос
/ 20 сентября 2009

В MySQL сортировка выполняется сервером баз данных, а не механизмом хранения.

Если в обоих случаях движок не смог предоставить результаты в уже отсортированном виде (это зависит от используемого индекса), сервер должен их отсортировать.

Единственная причина, по которой MyISAM / InnoDB могут отличаться, заключается в том, что порядок возврата строк может повлиять на то, как отсортированы данные - MyISAM может вернуть данные в «более отсортированном» порядке в некоторых случаи (и наоборот).

Тем не менее, сортировка строк 60 КБ не займет много времени, так как это очень маленький набор данных. Вы уверены, что ваш буфер сортировки достаточно большой?

Использование файловой сортировки на диске () вместо оперативной памяти намного медленнее. Двигатель, однако, не должен иметь никакого значения для этого. filesort - это не функция движка, а функция ядра MySQL. Файловая сортировка, на самом деле, отстой во многих отношениях, но обычно она не такая медленная.

0 голосов
/ 15 сентября 2009

Попробуйте добавить ключ для полей: metaward_achiever. alias_id, metaward_achiever. award_id и metaward_achiever. modified, это поможет много. И не используйте ключи на полях varchar, это увеличит время для вставок и обновлений. Также кажется, что у вас есть 77M записей в таблице achiever, вы можете позаботиться об оптимизации innodb. Есть много хороших учителей о том, как установить ограничения памяти для него.

...