Григорий Рубцов — руководитель проектов SQLinfo.ru (http://sqlinfo.ru/) и Webew.ru (http://webew.ru/), автор онлайн-курса по MySQL (http://sqlinfo.ru/classes/) и спикер конференции РИТ++.
Новое в Percona Server и MariaDB в сравнении с MySQL 5.5
Обзор возможностей:
— новое для разработчика;
— новое для администратора;
— улучшения производительности;
— миграция и вопросы совместимости.
Технические детали:
— хранилище XtraDB;
— Percona Tools;
— алгоритмы оптимизации подзапросов в MariaDB.
Александр Щепановский «Почему каждому языку нужен свой _»
SQL-ник DevDay. Рубцов. Новое в Percona Server и MariaDB в сравнении с MySQL 5.5
1. Новое в Percona Server и
MariaDB в сравнении с
MySQL 5.5
Григорий Рубцов
sakila@sqlinfo.ru
2. План доклада
– Введение. Percona Server и MariaDB
● Часть I. Обзор возможностей
– Новое для разработчика
– Новое для администратора
– Улучшение производительности
– Миграция
● Часть II. Технические детали
– Хранилище XtraDB
– Percona Tools
– Алгоритмы оптимизации подзапросов в
2
MariaDB
4. Percona Server
● Компания основана в августе 2006 года
Петром Зайцевым и Вадимом Ткаченко
● Специализация — производительность
MySQL http://percona.com
● Разработали патчи для улучшения
производительности MySQL, которые
вошли в состав Percona Server 4
5. Percona Server
● Percona Server = MySQL Community +
XtraDB + PT патчи + DBA патчи
● Полностью Open Source
● Версия соответствует версии MySQL:
Percona 5.5.21 на базе MySQL 5.5.21
● + Percona Tools — радикальное
5
усиление DBA (применимы и к MySQL)
6. MariaDB
● В 2008 году MySQL AB была куплена Sun
Microsystems (последняя поглощена
Oracle в 2009)
● Основатель MySQL Monty Widenius в
2009 выпустил fork MySQL: MariaDB
http://mariadb.org http://kb.askmonty.org
● Мотивация: развитие свободного MySQL
не должно останавливаться 6
7. MariaDB
● В MariaDB перерабатывается ядро
MySQL с исправлением архитектурных
проблем (многие остались еще от 3.23)
● MariaDB = переработанный код MySQL +
XtraDB + патчи от Percona + новые фичи
● Разрабатываются открытые аналоги
всех возможностей MySQL Enterprise
(например, pluggable authentication) 7
8. Связь проектов:
downstream
● Percona использует каждую новую
стабильную версию за основу и
применяет свои патчи + заменяет
InnoDB на XtraDB
● MariaDB основана на коде MySQL 5.1 (с
использованием dev-кода 6.0).
Возможности новых версий MySQL
встраиваются в код MariaDB.
● MariaDB использует XtraDB и многие
патчи Percona 8
9. Связь проектов:
upstream
● Percona и команда Monty - лидеры по
количеству баг-репортов MySQL.
Включая баги производительности,
баги InnoDB и критические баги ядра
(некоторые очень старые).
● Многие патчи от Percona и Monty
адаптируются и входят в MySQL:
микросек. slow_log в 5.5, улучшения
InnoDB, оптимизация подзапросов в 5.6
— параллельная разработка. 9
10. Новые функции и
новые баги
● Percona:
● улучшенная производительность и новый
движок XtraDB
● наследует баги и фиксы MySQL; новые баги
возможны в XtraDB
● MariaDB:
● улучшены алгоритмы выполнения запросов +
новые возможности (также, XtraDB)
● баги ядра не будут совпадать с MySQL — у
Монти собственная система QC 10
11. Системные требования
● 32 или 64-битная система (32-бит теряет
актуальность из-за ограничений
памяти)
● MySQL: Linux, FreeBSD, Solaris, Windows,
Mac OS X, source code
● Percona: Linux, source code
● MariaDB: Linux, Solaris, Windows, source
code
11
13. Новое для разработчика
● Percona:
● Плагин HandlerSocket: NoSQL доступ к базе
данных (также в MariaDB)
● динамическая длина строк в MEMORY-
таблицах
● MariaDB:
● виртуальные колонки и индексы на них
● динамические колонки
● неблокирующая клиентская библиотека
13
14. Плагин HandlerSocket
● Позволяет обращаться к XtraDB/InnoDB
таблицам по индексу с помощью
NOSQL протокола (без авторизации,
SQL-запроса и др.)
● Использует два дополнительных TCP-
порта: для чтения и записи
● mysql> INSTALL PLUGIN handlersocket
SONAME 'handlersocket.so';
● my.cnf: loose_handlersocket_port=9998
14
● my.cnf: loose_handlersocket_port_wr=9999
15. Плагин HandlerSocket
● Обращение с помощью клиентской
библиотеки (C++,Perl,PHP,Java,Python,..)
● Как это выглядит в PHP:
– $hs = new HandlerSocket($host, $port);
– $hs->openIndex(0, $dbname, $table,
HandlerSocket::PRIMARY, 'k,v'))
– $retval = $hs->executeSingle(0, '=', array('k1'));
– см. http://code.google.com/p/php-handlersocket/
● Доступны: GET, UPDATE, REMOVE
15
16. Виртуальные колонки
● CREATE TABLE money (
debit int NOT NULL,
credit int NOT NULL,
balance int AS (debit - credit)
PERSISTENT,
KEY(balance));
● Два типа: VIRTUAL и PERSISTENT,
индексы поддерживаются только на
последних
16
17. Динамические колонки
● CREATE TABLE people (
name varchar(100),
dynattr mediumblob);
● INSERT INTO people VALUES ('Ivan',
COLUMN_CREATE(1, 'tall', 2, 'blue eyes'));
● SELECT name, COLUMN_GET(dynattr, 1 AS
char) FROM people;
● | Ivan | tall |
● Ограничение: нельзя хранить blob в
динамических колонках
17
18. Неблокирующая
клиентская библиотека
– int mysql_real_query_start(&status, MYSQL, query,
query_length)
– int mysql_real_query_cont(&status, MYSQL,
wait_status)
● Возвращают 0, если запрос выполнен или не
ноль, если необходимо ожидание
● http://kb.askmonty.org/en/using-the-non-
blocking-library
● Появилась в MariaDB 5.5 (16.03.2012),
но работает также с MySQL и Percona
18
19. Динамические строки в
MEMORY-таблицах
● В MySQL в MEMORY-таблицах
запрещены blob-ы, а varchar(20)
хранится как char(20), занимая
максимальный объем
● Percona:
● CREATE TABLE articles ( id int, title
varchar(300), full text) ENGINE=MEMORY;
● MariaDB: планируется в 5.5.X, X>23
19
20. Новое для
администратора
● MariaDB:
● поддержка плагинов аутентификации
● Percona:
● работа с побившимися таблицами
● импорт отдельных таблиц из .ibd файлов
● транзакционность реплик
● улучшение диагностики
● улучшение лога медленных запросов
20
21. Хранилище по-умолчанию
● в MySQL 5.5 по умолчанию
используется InnoDB (в 5.1 — MyISAM)
● в Percona — по умолчанию XtraDB
(который называется InnoDB)
● в MariaDB — по умолчанию MyISAM
(разрабатывается Aria — пока бета)
● Параметр настраивается (в my.cnf)
● default_storage_engine=InnoDB
21
22. Работа с побившимися
таблицами
● В InnoDB можно использовать опцию
innodb_file_per_table
– Каждая таблица хранится в отдельном файле,
ссылка на который — в общем tablespace.
– Если таблица повреждена, то стандартный
InnoDB падает с ошибкой и все таблицы
становятся недоступны
● Percona:
– innodb_corrupt_table_action=warn
● В этом случае — прекращается доступ
только к одной таблице. 22
23. Импорт отдельных
таблиц из .ibd файлов
– В MySQL даже с использованием
innodb_file_per_table невозможно восстановить
таблицу из одного ibd-файла
● Percona:
– innobackupex позволяет отделить таблицу и
подключить ее бинарно к XtraDB(!) серверу
– $ xtrabackup --prepare --export —innodb-file-per-
table --target-dir=/data/backups/mysql/
– my.cnf: innodb_import_table_from_xtrabackup=1
● CREATE TABLE mytable (same structure);
● ALTER TABLE mytable DISCARD TABLESPACE;
● ALTER TABLE mytable IMPORT TABLESPACE; 23
24. Транзакционность реплик
● В MySQL, при внезапной остановке реплики
информация о выполненной транзакции
может не записаться в relay-log.info и
master.info. Репликация собъется.
● Percona:
● rpl_transaction_enabled=1
● статус репликации хранится в журнале
транзакций InnoDB.
24
25. Улучшение диагностики
● Percona: в SHOW PROCESSLIST
добавлены колонки статуса исполнения
– Rows_sent, Rows_examined, Rows_read
– MariaDB: добавлено время в мс, но нет rows*.
● Расширены
● SHOW ENGINE INNODB STATUS;
● INFORMATOION_SCHEMA:
– CLIENT_STATISTICS
– INDEX_STATISTICS (ROWS_READ)
25
– TABLE_STATISTICS
26. Лог медленных запросов
● Информация расширена
● # User@Host: mailboxer[mailboxer] @ [192.168.10.165]
# Thread_id: 11167745 Schema: board
# QC_Hit: No Full_scan: No Full_join: No Tmp_table: Yes Disk_tmp_table: No
# Filesort: Yes Disk_filesort: No Merge_passes: 0
# Query_time: 0.000659 Lock_time: 0.000070 Rows_sent: 0 Rows_examined: 30
Rows_affected: 0 Rows_read: 30
# innodb_IO_r_ops: 1 innodb_IO_r_bytes: 16384 innodb_IO_r_wait: 0.028487
# innodb_rec_lock_wait: 0.000000 innodb_queue_wait: 0.000000
# innodb_pages_distinct: 5
select count(distinct author_id) from art87.article87 force index (forum_id) where
forum_id = 240215 and thread_id = ``710575``
● Дополнительные настройки
● log_slow_filter=tmp_table_on_disk,filesort_on_disk
26
27. Улучшения
производительности
● Percona:
● улучшение масштабируемости и
устойчивости по отношению к нагрузкам
● улучшения в XtraDB по сравнению с
InnoDB (см. часть II)
● полностью отключаемый query_cache
● многое, не вошедшее в доклад
http://www.percona.com/doc/percona-
server/5.5/feature_comparison.html
27
28. Улучшения
производительности
● MariaDB:
● алгоритмы оптимизации подзапросов
(см. часть II)
● новые алгоритмы JOIN
● оптимизация index_condition_pushdown
● сегментированный key_cache
● групповой коммит при репликации
28
30. Полностью отключаемый
query_cache
● При большом количестве простых
запросов, query_cache может стать узким
местом, так как он работает в один поток
(общий mutex)
● query_cache_type=0
● в MySQL query_cache не работает, но mutex
используется
● в Percona в этом случае mutex отсутствует
(включение кэша потребует рестарт
сервера)
30
31. MariaDB — новые
алгоритмы
● Оптимизация подзапросов (см. часть II).
● Реализован классический алгоритм Hash
join: JOIN посредством промежуточного
построения хэш-таблицы для одной из
таблиц (работает для JOIN с оператором =).
● Улучшен алгоритм index_merge для
запросов с OR. WHERE City='Moscow' OR
Country='Germany';
31
32. index_condition_pushdown
● Пусть имеется составной ключ
KEY(key_col1, key_col2)
● SELECT * FROM tbl WHERE key_col1 between
10 and 11 and key_col2 like '%foo%';
● MySQL использует первую часть индекса
для выборки, а второе условие будет
проверять по данными таблицы (using
where)
● MariaDB проверит второе условие по
информации из индекса (using index
condition) 32
33. Групповой коммит при
репликации
● Реплика выполняет все транзакции в
один тред, поэтому в ряде случаев
может отставать
● Чтобы ускорить работу реплики,
сохранив надежность, выполняется
общий коммит для группы транзакций
и делается fsync()
– Важно при innodb_flush_logs_at_trx_commit=1
● Опция работает по-умолчанию
33
34. Миграция на
Percona/MariaDB
● Поддерживается совместимость:
● на уровне SQL
● на бинарном уровне
● Модификация приложений не требуется
● Репликация:
● Slave может быть на одну версию новее
мастера (5.0 -> 5.1, 5.1 -> 5.5)
● http://www.percona.com/doc/percona-
server/5.5/upgrading_guide_51_55.html 34
35. Порядок миграции
● сделать backup (mysqldump /
innobackupex)
● заменить MySQL на Percona Server или
MariaDB, сохранив my.cnf
● запустить mysqld с опцией --skip-grant-
tables
● запустить скрипт mysql_upgrade - может
занять время (выполняет check table *.*)
● перезапустить mysqld
35
36. Миграция обратно
● Данные: в общем случае —
восстановление из дампа
● Приложения: если не использовали
возможности, не доступные в MySQL
● Если не использовались
несовместимые оцпии XtraDB (см. часть
II), данные обладают бинарной
обратной совместимостью
36
40. Настраиваемый Insert
buffer
● Для неуникальных индексов, InnoDB
накапливает обновление страниц индекса в
Insert buffer
● Стандартное поведение — сбрасывать Insert
buffer на диск, когда наполнится или при
обращении на чтение
– innodb_ibuf_active_merge=1 разрешает
сбрасывать на диск ненаполненный буфер
– innodb_ibuf_max_size — позволяет настроить
размер (по умолчанию - половина
innodb_buffer_pool_size, что может быть
слишком много) 40
41. Масштабируемость ввода-
вывода
● Дисковый ввод-вывод стал многопоточным:
● innodb_read_io_threads
● Innodb_write_io_threads
– По умолчанию 1, но на RAID-системах имеет смысл
записывать и читать в несколько потоков
● Добавилось много параметров конфигурации:
● innodb_flush_log_at_trx_commit_session
– 0 flush раз в секунду
– 1 flush после каждого commit
– 2 запись после commit, но не делать flush
– 3(default) использовать значение глобальной настройки
innodb_flush_log_at_trx_commit 41
42. Партиционирование
adaptive hash index
● Для ускорения запросов InnoDB на свое
усмотрение может создавать hash-
индекс в памяти
● Новый параметр:
● innodb_adaptive_hash_index_partitions
– по умолчанию 1
● позволяет партиционировать хэш-индексы
и сделать обращения к ним
многопоточными
42
43. Сохранение LRU
● При перезапуске сервера, innodb_buffer_pool
обнуляется и разогрев кэша может занимать
много времени (производительность низкая
пока не разогрелся)
● В Percona появилась возможность сохранить
содержимое buffer_pool (номера страниц) на
диск в файл ib_lru_dump, а потом быстро
загрузить в память при старте:
● innodb_auto_lru_dump=1
43
44. Несовместимые
параметры XtraDB
● innodb_page_size — по умолчанию 16kb
– можно уменьшить, например для SSD или
увеличить для дисковых накопителей
– изменение параметра требует пересоздание
tablespace (случайно изменить невозможно)
● innodb_expand_undo_slots=on
– по-умолчанию InnoDB поддерживает не более
1023 одновременных транзакций; опция
превращает ограничение в 4072
● innodb_extra_rsegments
– увеличение количества сегментов отката 44
46. innobackupex
● Open source замена mysqlbackup,
доступной только в Enterprise версии.
● Инкрементальное резервное
копирование (InnoDB).
● Отделение отдельных InnoDB-таблиц.
● Может использоваться для MySQL.
● Пример: настройка реплики без
остановки мастера.
46
47. Алгоритмы оптимизации
подзапросов в MariaDB
● Подзапросы в MySQL
● Подзапросы типа semi-join
● Обзор новых алгоритмов MariaDB
● Материализация и кэширование
● Индексы на временных таблицах для
подзапросов в поле FROM
47
48. Подзапросы в MySQL
● Подзапросы в поле FROM используют
временную таблицу
● Подзапросы с IN/ALL/ANY/SOME используют 2
вида преобразования:
● IN → EXISTS
● MIN/MAX
● затем прямое выполнение
● Остальные: прямое многократное
исполнение (кэш для результата
независимых запросов; план исполнения
48
используется повторно)
49. IN → EXISTS
● outer_expr IN (SELECT inner_expr FROM ...
WHERE subquery_where)
=> EXISTS (SELECT 1 FROM ... WHERE
subquery_where AND outer_expr=inner_expr)
● Порядок исполнения всегда от внешнего к
внутреннему
● MySQL часто применяет метод по ошибке к
независимому подзапросу и он исполняется
как зависимый (много раз)
49
50. MIN/MAX
● Для подзапросов вида
value {ALL|ANY|SOME} {> | < | >= | <=}
(uncorrelated subquery)
преобразование с использованием
min/max
WHERE 5 > ALL (SELECT x FROM t)
WHERE 5 > (SELECT MAX(x) FROM t)
50
52. Пример semi-join запроса
● Пример: выбрать все европейские страны, в которых
есть город с населением больше миллиона:
● SELECT * FROM Country WHERE Continent='Europe' AND
Country.Code IN (SELECT City.country FROM City WHERE
City.Population>1000*1000);
– алгоритмически возможно два порядка исполнения
52
53. Отличие от JOIN
● Отличие от JOIN — отсутствие дубликатов;
интересует информация только из одной таблицы
● SELECT * FROM Country WHERE Continent='Europe' AND
Country.Code IN (SELECT City.country FROM City WHERE
City.Population>1000*1000);
● Эквивалентный JOIN с DISTINCT:
● SELECT DISTINCT Country.* FROM Country JOIN City ON
City.country=Country.Code WHERE
City.Population>1000*1000;
● MariaDB выполняет подзапрос специальным алгоритмом
semi-join, который эффективнее эквивалентного запроса,
так как последний для DISTINCT делает группировку
результата, а semi-join исключает дубликаты по ходу. 53
55. Алгоритмы MariaDB: обзор
● Semi-join выполнятся нативно и это
быстрее, чем эквивалентный JOIN.
● Semi-join выбирает порядок outer-to-
inner или inner-to-outer
● MySQL всегда выполняет подчиненный
подзапрос до объединения внешней
таблицы с третьей таблицей. MariaDB
может выполнить сначала внешний
JOIN, а затем подзапрос.
55
56. Материализация
SELECT * FROM Country WHERE Country.code IN
(SELECT City.Country FROM City WHERE City.Population
> 7000000) AND Country.continent='Europe'
● Два направления объединения
56
57. Оптимизация
подзапросов FROM
Два алгоритма для оптимизации
подзапросов в части FROM:
● Derived table merge
● Derived table with keys
57
58. Derived table merge
SELECT * FROM (SELECT * FROM City WHERE
Population > 10*1000) AS big_city WHERE
big_city.Country='DEU';
MariaDB преобразует в
SELECT * FROM City WHERE Population >
10*1000 AND big_city.Country='DEU';
58
59. Derived table with keys
SELECT * FROM Country,
(SELECT City.Country, sum(City.Population) as
urban_population FROM City GROUP BY
City.Country HAVING urban_population >
1*1000*1000) as cities_in_country
WHERE
Country.Code=cities_in_country.Country AND
Country.Continent='Europe';
59
60. Derived table with keys
id select_type table type key key_len ref rows
1 PRIMARY Country ref Population 17 NULL 60
1 PRIMARY < derived2> ref key0 3 world.Country.Code 17
2 DERIVED City ALL NULL null 4069
60
61. Спасибо за внимание!
● приходите на форум SQLinfo.ru/forum/
● пишите на sakila@sqlinfo.ru
● Также:
● Услуги по оптимизации MySQL
● Онлайн-курс «Оптимизация
производительности MySQL»
61