Действительно ли сортировка InnoDB ТАКАЯ медленная?

StackOverflow https://stackoverflow.com/questions/1428678

Вопрос

У меня были все мои таблицы в 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
Это было полезно?

Решение

Это большой набор результатов (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

Другие советы

Как написано в Следует ли вам перейти с MyISAM на Innodb ? (который появился довольно недавно):

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

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

Наиболее важными из них являются:

innodb_буффер_пульс_размер 70-80% памяти - это безопасная ставка.Я установил его на 12G на 16GB box.

Обновить:Если вы хотите узнать больше подробностей, ознакомьтесь с подробным руководством по настройка буферного пула innodb

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

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

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

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

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

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

Также проверьте, может ли ваше приложение запускаться в режиме изоляции с фиксацией ЧТЕНИЯ - если это так – установите его по умолчанию как transaction-isolation=READ-COMMITTED.Этот параметр имеет некоторые преимущества в производительности, особенно при блокировке в версии 5.0 и даже больше, если использовать MySQL 5.1 и репликацию на уровне строк.

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

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

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

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

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

Оптимизатор запросов 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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top