Рассматривая особенно раздражающий запрос к таблицам MyISAM, который несколько раз занимал много времени, я заметил, что MySQL, похоже, демонстрирует довольно странный шаблон ввода-вывода: при выполнении одного запроса и необходимости выполнения значительного количество операций ввода-вывода (например, для сканирования таблицы или когда кэш-память пуста в результате того, echo 3 > /proc/sys/vm/drop_caches
что индексы должны быть сначала загружены с диска), размер очереди для базового блочного устройства близок к значению 1, с ужасающей производительностью всего 4-5 МБ / с:
root@mysql-test:~# iostat -xdm 5 /dev/sda
Linux 3.2.0-40-generic (mysql-test) 04/30/2014 _x86_64_ (4 CPU)
Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.14 24.82 18.26 88.79 0.75 4.61 102.56 2.83 26.39 19.29 27.85 2.46 26.31
Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.00 69.29 151.52 72.73 5.31 0.59 53.95 1.21 5.39 7.84 0.29 4.39 98.51
Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.00 153.06 144.29 174.69 4.96 1.36 40.54 1.39 4.36 8.91 0.60 3.15 100.49
Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.00 105.75 150.92 109.03 4.53 0.85 42.41 1.29 4.96 8.15 0.54 3.90 101.36
Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.00 48.89 156.36 51.72 5.28 0.76 59.38 1.28 6.16 8.02 0.55 4.77 99.23
Хотя 150 операций ввода-вывода в секунду просто являются тем, что может обеспечить один диск в данной конфигурации с точки зрения случайного ввода-вывода, результат все еще действительно удивляет меня, так как я ожидаю, что MySQL сможет выполнять асинхронный ввод-вывод для чтения и извлечения большое количество блоков одновременно вместо того, чтобы читать и оценивать их один за другим, фактически игнорируя преимущества распараллеливания, доступные в конфигурациях RAID. Какое проектное решение или вариант конфигурации отвечает за это? Это проблема для конкретной платформы?
Несмотря на то, что я проверил это с таблицами MyISAM большого размера, я вижу аналогичные эффекты с теми же таблицами, преобразованными в InnoDB (хотя и не так плохо, пример запроса по-прежнему занимает 20-30 секунд, при этом большая часть времени уходит на чтение диска с длина очереди 1) после перезапуска демона mysql и поэтому пулы буферов пусты. Я также проверил, что та же проблема сохраняется на 5,6 ГА и текущем 5,7 этапе 14 - пока я использую один поток запросов, MySQL, похоже, не может распараллелить операции ввода-вывода, необходимые для обработки запросов.
По запросу некоторые дополнительные детали по сценарию. Поведение можно наблюдать с множеством типов запросов. Я произвольно выбрал один для дальнейшего тестирования, который выглядит примерно так:
SELECT herp.id, herp.firstname, herp.lastname, derp.label, herp.email,
(SELECT CONCAT(label, " (", zip_code, " ", city,")" ) FROM subsidiaries WHERE subsidiaries.id=herp.subsidiary_id ) AS subsidiary,
(SELECT COUNT(fk_herp) from herp_missing_data WHERE fk_herp=herp.id) AS missing_data
FROM herp LEFT JOIN derp ON derp.id=herp.fk_derp
WHERE (herp.fk_pools='123456') AND herp.city LIKE '%Some City%' AND herp.active='yes'
ORDER BY herp.id desc LIMIT 0,10;
Я знаю, что в нем есть место для оптимизации, но я решил оставить это по ряду причин и сосредоточиться на поиске общего объяснения неожиданной схемы ввода-вывода, которую я вижу.
В используемых таблицах есть куча данных:
mysql> select table_name, engine, table_rows, data_length, index_length from information_schema.tables WHERE tables.TABLE_SCHEMA = 'mydb' and tables.table_name in ( 'herp', 'derp', 'missing_data', 'subsidiaries');
+-------------------------+--------+------------+-------------+--------------+
| table_name | engine | table_rows | data_length | index_length |
+-------------------------+--------+------------+-------------+--------------+
| derp | MyISAM | 14085 | 1118676 | 165888 |
| herp | MyISAM | 821747 | 828106512 | 568057856 |
| missing_data | MyISAM | 1220186 | 15862418 | 29238272 |
| subsidiaries | MyISAM | 1499 | 6490308 | 103424 |
+-------------------------+--------+------------+-------------+--------------+
4 rows in set (0.00 sec)
Теперь, когда я выполняю запрос выше по этим таблицам, я получаю время выполнения более 1 минуты, в то время как система, очевидно, постоянно занята чтением данных с диска одним потоком.
Профиль для примера выполнения запроса (который в этом примере занял 1 мин 9,17 с) выглядит следующим образом:
mysql> show profile for query 1;
+--------------------------------+-----------+
| Status | Duration |
+--------------------------------+-----------+
| starting | 0.000118 |
| Waiting for query cache lock | 0.000035 |
| init | 0.000033 |
| checking query cache for query | 0.000399 |
| checking permissions | 0.000077 |
| checking permissions | 0.000030 |
| checking permissions | 0.000031 |
| checking permissions | 0.000035 |
| Opening tables | 0.000158 |
| init | 0.000294 |
| System lock | 0.000056 |
| Waiting for query cache lock | 0.000032 |
| System lock | 0.000116 |
| optimizing | 0.000063 |
| statistics | 0.001964 |
| preparing | 0.000104 |
| Sorting result | 0.000033 |
| executing | 0.000030 |
| Sending data | 2.031349 |
| optimizing | 0.000054 |
| statistics | 0.000039 |
| preparing | 0.000024 |
| executing | 0.000013 |
| Sending data | 0.000044 |
| optimizing | 0.000017 |
| statistics | 0.000021 |
| preparing | 0.000019 |
| executing | 0.000013 |
| Sending data | 21.477528 |
| executing | 0.000070 |
| Sending data | 0.000075 |
| executing | 0.000027 |
| Sending data | 45.692623 |
| end | 0.000076 |
| query end | 0.000036 |
| closing tables | 0.000109 |
| freeing items | 0.000067 |
| Waiting for query cache lock | 0.000038 |
| freeing items | 0.000080 |
| Waiting for query cache lock | 0.000044 |
| freeing items | 0.000037 |
| storing result in query cache | 0.000033 |
| logging slow query | 0.000103 |
| cleaning up | 0.000073 |
+--------------------------------+-----------+
44 rows in set, 1 warning (0.00 sec)
источник
Ответы:
Сначала позвольте мне уточнить, подтвердив, что MyISAM не выполняет асинхронный ввод-вывод, но InnoDB делает и будет по умолчанию из MySQL 5.5. До 5.5 он использовал «имитацию AIO» с использованием рабочих потоков.
Я думаю, что также важно различать три ситуации:
Для (1) I / O сможет выполнять параллельно для этого. У MyISAM есть некоторые ограничения: блокировка таблиц и глобальная блокировка
key_buffer
(индексный кеш). InnoDB в MySQL 5.5+ действительно светит здесь.Для (2) это в настоящее время не поддерживается. Хороший вариант использования был бы с разделением, где вы могли бы искать каждую разделенную таблицу параллельно.
Для (3) InnoDB имеет линейное упреждающее чтение для полного чтения (группа из 64 страниц), если читается> 56 страниц (это настраивается), но есть место для дальнейшего улучшения. Facebook написал о внедрении логического чтения в их ветке (с 10-кратным увеличением производительности при сканировании таблиц).
источник
Я надеюсь, что
missing_data
это не MyISAM, потому что пустая таблица MyISAM обычно имеет 1024 байта.MYI
. От MyISAM ожидается ненулевой размер байта. Нулевой байт.MYI
звучит немного жутко для меня.Если вы запустите этот запрос метаданных
и движок этой таблицы - MyISAM, вам нужно починить его.
Боковое примечание: если
engine
естьNULL
, это вид. Если это представление или это не MyISAM, пожалуйста, проигнорируйте оставшуюся часть моего поста и добавьте эту информацию к вопросу. Если таблица MyISAM, читайте дальше ...Согласно вашему запросу метаданных,
missing_data.MYD
это около 46M.Во-первых, запустите это
Вы получите либо описание таблицы, либо сообщение об ошибке, говорящее что-то вроде
Если вы получили описание таблицы и это MyISAM, пожалуйста, запустите
Он будет воссоздавать таблицу без фрагментации и вычислять новую статистику индекса. Если это не работает, попробуйте:
Это должно восстановить страницы индекса для MyISAM.
На всякий случай (если вы используете MySQL 5.6), запустите это после восстановления
Ваш вопрос
Индексы вашей таблицы могут быть не загружены в память, если MySQL Query Optimizer решит не использовать. Если ваше предложение WHERE диктует, что из индексов должно быть прочитано значительное количество строк, MySQL Query Optimizer увидит это при построении плана EXPLAIN и решит использовать вместо этого полное сканирование таблицы.
Параллельные операции ввода-вывода в таблице MyISAM недостижимы, поскольку не поддаются настройке.
InnoDB может быть настроен для увеличения производительности, как это.
источник