Эффективный MySQL

Preview:

DESCRIPTION

Доступна масса информации по основам оптимизации MySQL, однако среднестатистический разработчик по-прежнему склонен ее по большей части игнорировать :(. Цель семинара — еще раз обратить внимание на такие базовые вещи, как выбор оптимальных типов полей, основны построения эффективных индексов, доступные средства обеспечения ссылочной целостности. Выполнен обзор инструментов оптимизации, доступных разработчику, особое внимание уделено pt-query-digest в варианте processlist, позволяющая разработчику самостоятельно выполнить анализ производительности и обнаружить узкие места.

Citation preview

Эффективный MySQL

Interlabs

13 мая 2013

1 / 35

Немного истории

MySQL AB4.0 03.2003 UNION . . .

4.1 06.2004 BTREE, PREPARED, SUBQUERY . . .

5.0 09.2005 CURSOR, VIEW, TRIGGER . . .

SUN Microsystems 5.1 11.2008 PARTITIONING . . .

ORACLE 5.5 9.2010 DEFAULT INNODB, SIGNAL . . .

5.6 dev 2011 NOSQL, PERFORMANCE SCHEMA . . .

MariaDB — полностью совместимый свободный форк:

• InnoDB→ XtraDB

• динамические и виртуальныеколонки

• SphinxSE — встроенный Sphinx

• много оптимизаций, включаяподзапросы

2 / 35

Типы данных

• чем меньше места — тем лучше;• чем проще тип — тем лучше;• колонка с NULL: больше места, дольшеобработка, сложнее оптимизация.

Используем минимально достаточныйсамый простой тип, избегаем NULL.

3 / 35

ЧислаИспользуем минимально достаточный тип:

TINYINT 255

SMALLINT 65535

MEDIUMINT 16777215

INT 4294967295

BIGINT 18446744073709551615M

FLOAT 1.175494351E–38

3.402823466E+38

DOUBLE 2.2250738585072014E–308

1.7976931348623157E+308

DECIMAL 65 цифр

• по возможности UNSIGNED• по возможности FLOAT, диапазон DOUBLE редко нужен• важна точная дробная часть — DECIMAL

4 / 35

СтрокиCHAR

• фиксированный размер• 0 - 255• быстрое изменение

VARCHAR

• размер строки + 1–2 байта• 0 - 65535• дольше измeнение

Использование:

• часто изменяемые данные• незначительная разница вдлине строк

• относительно редкоеобновление

• строки различной длины

5 / 35

Бинарные строки

BINARY / VARBINARY

• просто набор байтов, не используют collation и UTF;• быстрее обрабатываются, занимают меньше места;• в остальном аналогичны CHAR и VARCHAR.

MD5, почтовые индексы, IP-адреса

6 / 35

Даты

DATE 1000–01–01 — 9999–12–31

TIMESTAMP 1970–01–01 00:00:01 UTC — 2038–01–19 03:14:07 UTC

DATETIME 1000–01–01 00:00:00 — 9999–12–31 23:59:59

• если позволяет временной интервал — TIMESTAMP• поведение TIMESTAMP при INSERT/UPDATE настраивается• DATETIME — в два раза больше места, но без ограничений

7 / 35

Тексты

TEXT = BLOB + encoding + collation

• отдельный способ хранения по отношению к другимполям, отдельное хранилище в InnoDB;

• индексируется только часть (max_sort_length);• снижение производительности при сложных запросах;• можно настраивать длину: TINYTEXT, MEDIUMTEXT,SMALLBLOB и т.д.

Использовать только если действительно нужно.

8 / 35

Механизмы храненияMyISAM Memory Archive CSV . . . InnoDB (XtraDB)

• ручное восстановление• нет ссылочной целостности• нет транзакций• полнотекстовые индексы

• высокая надежность• кластеризованный индекс• ссылочная целостность• хранимый код, транзакции

. . . из всех для нас важнейшим является InnoDB

Всегда явно прописываем при создании таблиц.

9 / 35

Индексы

Проектирование базы основано на данных, нопроектирование индексов основано на запросах

• анализ запросов, генерируемых приложением• анализ лога (медленных) запросов

SET GLOBAL log_slow_queries = ’ON’;SET GLOBAL long_query_time = 0;$ pt-query-digest /var/lib/mysql/mysql-slow.log...

10 / 35

SHOW STATUS

Можно получить различную статистику текущего соединения:

SHOW PROCESSLIST;SHOW TABLE STATUS;SHOW TABLE STATUS FROM database WHERE Engine=’InnoDB’;

FLASH STATUSSHOW SESSION STATUS LIKE ’Select%’;SHOW SESSION STATUS LIKE ’Created%’;FLASH STATUS;

11 / 35

Лог медленных запросовМожно включать и выключать без перезапуска сервера,результат в таблицу:

SET GLOBAL log_slow_queries = ’ON’;SET GLOBAL long_query_time = 2;SET GLOBAL log_output = ’TABLE’;SET GLOBAL log_queries_not_using_indexes = ’ON’;

SELECT start_time, query_time, rows_set, rows_examined, sql_textFROM mysql.slow_logWHERE db = ’database’;

12 / 35

Профайлер

Время выполнения всех стадий обработки запроса, может бытьполезно для сложных запросов:

SET profiling=1;SELECT ...SHOW PROFILES;SHOW PROFILE FOR QUERY 1;SHOW PROFILE CPU FOR QUERY 1;...

13 / 35

INFORMATION SCHEMA

Количество записей в каждой таблицы базы:

SELECT TABLE_NAME, TABLE_ROWSFROM INFORMATION_SCHEMA.TABLESWHERE TABLE_SCHEMA=’database’ORDER BY TABLE_ROWS DESC;

Некоторые запросы уже реализованы в проекте CommonSchema.

14 / 35

Common Schemahttps://code.google.com/p/common-schema/

• реально сносит крышу, «jQuery для MySQL» ,• библиотека функций + скриптовый язык, реализованныйна хранимых

• отладчик для хранимых процедур• набор view для стандартных задач анализа и оптимизации

foreach($table, $schema, $engine: table in dbname){

if ($engine = ’InnoDB’)ALTER TABLE :$schema.:$table ENGINE=InnoDB ROW_FORMAT=Compact;

}

15 / 35

Percona Toolkit

• pt-query-digest — поиск проблемных запросов• pt-index-usage — анализ использования индексов• pt-duplicate-key-checker — поиск дублирующихсяиндексов

http://www.percona.com/software/percona-toolkit

16 / 35

pt-query-digestНе обязательно использовать серверный slow log, можнополучить клиентский с помощью PROCESSLIST:

$ pt-query-digest --processlisth=mysql.interlabs.lan,u=devel,p=password--interval=0.01 --output slowlog > slow.log

$ pt-query-digest --explainh=mysql.interlabs.lan,u=devel,p=password > explained.log

explained.log — отчет об анализе slow.log:

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

17 / 35

pt-index-usage и другие

Анализирует slow.log и находит бесполезные индексы:

$ pt-index-usage --host=mysql.interlabs.lan--user=user --password=password slow.log

ALTER TABLE ‘db‘.‘table‘ DROP KEY ‘keyname‘;ALTER TABLE ‘db‘.‘another‘ DROP KEY ‘somekey‘;...

А также: pt-duplicate-key-checker, pt-table-usage и т.д.

18 / 35

Выбор индекса• запрос без подзапросов — один индекс• оптимизатор выбирает наиболее подходящий, учитываясодержимое таблицы

• проверка использования — поле key в EXPLAIN

ANALYZE TABLE tablename;

cardinality = количество разных значенийselectivity = cardinality / общее количество значений

• чем больше индексов — тем сложнее оптимизатору• оптимизация — только на таблице с реальными данными

19 / 35

СелективностьSELECT ... FROM table WHERE x = 3;INDEX(x)

• несколько значений равно 3 — используется• 10–30% равно 3 — возможно используется• большее количество — не используется

INDEX(gender), INDEX(is_active) . . . — бесполезны

SELECT * FROM information_schema.statistics

20 / 35

InnoDB: первичный ключ• UINIQUE и NOT NULL• хранит не только значения ключа, но и данные• обязателен, не указан — используется первый уникальныйили генерируется автоматически, но так делать не надо;

• последовательность должна соответствовать порядкудобавления записей, иначе неэффективная вставка;

• каждый вторичный ключ включает в себя поля первичного.

PRIMARY KEY(id)INDEX(id,x) и UNIQUE(id,x) — обычно бесполезныPRIMARY KEY(UUID) — проблема

21 / 35

Покрывающие индексы• если выбираем только поля, содержащиеся в индексе, кзаписи обращаться не нужно

• covering index, Using index в EXPLAIN• самый производительный вариант• дополнительное место, расходы при вставке

SELECT age FROM peopleWHERE first = ’John’ AND last = ’Doe’

INDEX(first, last) — работает при поискеINDEX(first, last, age) — covering index

22 / 35

Оптимальный индекс1 Все поля в WHERE, для которых =, в порядке убыванияселективности

2 Поле по которому:• WHERE range (BETWEEN, >, ...)• GROUP BY• ORDER BY — нужно учитывать порядок полей в ORDER BY

3 Дополнительные поля для covering index

SELECT a,b FROM t WHERE c=1SELECT b FROM t WHERE c=1 ORDER BY aSELECT b FROM t WHERE c=1 GROUP BY aINDEX(c,a,b)

23 / 35

GROUP BY ORDER BYСоставной индекс удовлетворяет WHERE и есть еще поля виндексе — GROUP BY и ORDER BY (чаще что-то одно):

WHERE a=1 GROUP BY bWHERE a=1 ORDER BY bWHERE a=1 GROUP BY b ORDER BY bINDEX(a,b) — все работает

WHERE a=1 GROUP BY b ORDER BY cINDEX(a,b,c) — то же, что INDEX(a,b),

если не covering

WHERE b=1 AND a > 9 ORDER BY aINDEX(b,a) — работает

24 / 35

ORDER BY LIMIT

• если ORDER BY использует индекс — LIMIT эффективный• иначе — обход всех записей

SELECT SQL_CALC_FOUND_ROWS ... LIMIT 10;SELECT FOUND_ROWS();

Позволяет избежать повторного SELECT с COUNT(), данные попроизводительности противоречивы.

25 / 35

Когда индексы не работают

NOT

• NOT LIKE• NOT IN• NOT (expression)• <>

IN

• IN (SELECT ...)• IN (1,2,3)оптимизируется как =

Функции WHERE YEAR(date) = ’2013’

OR в WHERE WHERE first = ’John’ OR last = ’Smith’

LIKE работает только для префиксов LIKE ’John%’.

26 / 35

Проблемы с сортировкой

Сортировка не использует индекс, если:

• нарушается префиксность индекса• колонка из другой таблицы или не в индексе• разнонаправленная сортировка для разных колонок• сортировка выборки не соответствует сортировке индекса• GROUP BY и ORDER BY по разным полям (с большойвероятностью)

27 / 35

Индексы: антипаттерны

• отсутствующие индексы• индексы не учитывающие селективность• дублирующиеся индексы, или индексы входящие в другиеиндексы — сложнее оптимизатору, больше затраты приизменении

• много индексов по одиночным колонкам — оптимизаторвыберет один

• отсутствие covering-индексов• избыточные covering-индексы• FULLTEXT search

28 / 35

EXPLAIN SELECTОсновной инструмент диагностики запроса

• Using index — используется покрывающий индекс;• Using where — применяется WHERE, используется ли приэтом индекс — смотри в possible_keys и key

• Using temporary — временная таблица в памяти или надиске

• Using filesort — сортировка не может быть выполнена поиндексу, file тут не при чем.

В случае filesort может использоваться файл, если данныесортировки не помещаются в соответствующий буфер в памяти.

29 / 35

Некоторые рекомендации• ORDER BY NULL помогает избежать неявной сортировки• OR можно оптимизировать, переписав в UNION• всегда явно указываем UNION ALL и UNION DISTINCT,иначе выполняется DISTINCT

• JOIN обычно лучше оптимизируется, чем подзапросы• подзапросы могут быть средством оптимизации, если вних есть агрегирование

• чем больше OFFSET, тем медленнее• DISTINCT и GROUP BY не имеют смысла вместе

В ряде случаев — только денормализация

30 / 35

Главное в базе это. . .

Целостность данных

Вы всегда должны быть уверены в полноте и корректностиданных, хранимых в базе.

• первичный ключ;• уникальные ключи;• типы колонок;

• внешние ключи;• ограничения;• иногда триггеры.

31 / 35

Уникальные ключи

Всегда создаем, если поле подразумевает уникальность,позволяет отследить ошибки в данных сразу, а не когда втаблице сотни тысяч записей.

CREATE UNIQUE INDEX table_field ON table(field);

ALTER TABLE table ADD UNIQUE (field);

ALTER IGNORE table ADD UNIQUE (field);остается только первая дублирующаяся запись.

32 / 35

Уникальные ключи:обработка ошибок

INSERT INTO table (md5, stuff) VALUES($a, $b)ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id);

$id = SELECT LAST_INSERT_ID();

Удобно, но AUTOINCREMENT продолжает расти при ошибках!

33 / 35

InnoDB: внешние ключиCREATE TABLE users ...

FOREIGN KEY fk_group(group_id)REFERENCES groups(id)ON UPDATE CASCADE ON DELETE RESTRICT

• ON UPDATE CASCADE: если изменяется groups.id, тоизменяется и group_id

• ON DELETE RESTRICT: из groups нельзя удалить запись,если есть ссылающиеся записи

• ON DELETE CASCADE: если из groups удаляется запись,ссылающиеся удаляются автоматически

• при использовании REPLACE возможны проблемы

Не зависит от клиентского кода, использовать обязательно!34 / 35

Что читать

• High Performance MySQL1 — книга по оптимизации• PerconaConf 2013 slides2, особенно доклады пооптимизации

• MySQL Documents by Rick James3, нетривиальные рецептыпо решению различных проблем

• Percona Toolkit4

• Common Schema5

1http://shop.oreilly.com/product/9780596101718.do2http://form.percona.com/PLMCE13Slides.html3http://http://mysql.rjweb.org/4http://www.percona.com/software/percona-toolkit5https://code.google.com/p/common-schema/

35 / 35

Recommended