Слайд 1 - SQLinfo.ru

advertisement
Подходы к оптимизации
производительности MySQL
Григорий Рубцов
MySQL AB / Sun Microsystems
О чем доклад?
• Имеем приложение, использующее MySQL.
• Нагрузка выросла, производительность упала.
• Что можно с этим сделать на уровне MySQL?
План доклада (1/2)
I.
Диагностика. Насколько все плохо?
II.
Помогут ли индексы?
III. Запрос №1: ORDER BY + LIMIT
IV.
Безобидные подзапросы
План доклада (2/2)
V.
Где хранить? MyISAM, InnoDB, MEMORY, Cluster…
VI.
Кэш запросов MySQL
VII. Структура БД – её надо менять?!
VIII. Выводы
Приобретение MySQL компанией Sun
•
•
•
Сделка завершилась в 2008 году
Sun и MySQL совместными усилиями сделают продукты и услуги
ближе к заказчику.
– Корпоративная поддержка 24x7x365
– Больше поддерживаемых платформ
– Профессиональные услуги и обучение
Обе компании твердо стоят на позициях Open Source
Миссия Sun/MySQL:
Сделать доступную каждому высококлассную СУБД.
I.
Диагностика (1/2)
• Внешние признаки
– медленная работа приложения на сложных
операциях (поиск, сортировка данных)
– ошибка базы данных “too many connections”
– mysql активно использует процессор (десятки
процентов в top)
I.
Диагностика (2/2)
•
Преждевременная оптимизация – корень всех зол
•
Тони Хоар
• Внутренние признаки
– SHOW FULL PROCESSLIST; показывает
много процессов в состоянии locked или
просто много процессов
– много медленных запросов в логе (требует
параметров my.cnf)
• log-slow-queries
• long_query_time=1
Архитектура MySQL-сервера
II. Индексы (B-tree)
Root Node
(non-leaf)
Pointers to
child leaf
nodes
20
1
Keys
2-19
19
21
40
Keys
22-39
39
60
41
Leaf
Nodes
Keys
42-59
59
Pointers to
data pages
Key
Values
Actual
Data Pages
61
Keys
62-79
79
II. Составные индексы
• KEY(`фамилия`, `имя`) – аналог телефонной
книги, нельзя искать по имени (сначала надо
найти фамилию, а затем имя)
• KEY(A,B,C)
– позволяет:
• WHERE A=10 AND B>10;
• WHERE A=10 AND B=7 AND C=12;
• WHERE A=10 AND B=7 ORDER BY C
– не позволяет
• WHERE B=10;
• WHERE A=10 AND B>10 AND C>10
– Операция сравнения последняя при использовании индекса
II. Типы индексов
•
•
•
•
•
B-TREE (MyISAM, MEMORY, ndbcluster)
B+TREE (Innodb)
HASH (MEMORY, ndbcluster)
FULLTEXT (MyISAM)
SPATIAL (MyISAM)
•
mysql> SHOW INDEX FROM brevno_sessions\G
•
•
•
•
•
•
•
•
•
•
•
•
*************************** 1. row ***************************
Table: brevno_sessions
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: id
Collation: A
Cardinality: 244002
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
III. ORDER BY + LIMIT (1/8)
• Запрос №1 среди медленных в рунете:
– Выборка из большой таблицы
– Условие WHERE или ORDER BY не может
использовать ключи
– Сортируется много записей, а выбирается
несколько (например, LIMIT 20 )
III. ORDER BY + LIMIT (2/8)
• Пример 1:
– SELECT * FROM banners
WHERE active AND btype IN (1, 3, 7)
AND clicks < clickslim
AND shows < showslim
AND now() < date_end
AND now() > date_start
ORDER BY rand()*weight() LIMIT 1;
III. ORDER BY + LIMIT (3/8)
•Пример 2:
SELECT DISTINCT * FROM wp_posts
LEFT JOIN wp_post2cat
ON (wp_posts.ID = wp_post2cat.post_id)
LEFT JOIN wp_categories
ON (wp_post2cat.category_id = wp_categories.cat_ID)
WHERE 1=1 AND (category_id = '1')
AND post_date_gmt <= '2008-09-12 00:15:59'
AND (post_status = 'publish')
AND post_status != 'attachment' GROUP BY wp_posts.ID
ORDER BY post_date DESC LIMIT 3, 3;
III. ORDER BY + LIMIT (4/8)
• EXPLAIN SELECT …
id: 1
select_type: SIMPLE
table: wp_posts
type: ref
possible_keys: PRIMARY,post_status,post_date_gmt
key: post_status
key_len: 1
ref: const
rows: 3450
Extra: Using where; Using temporary; Using
filesort
.......................
III. ORDER BY + LIMIT (5/8)
• Как выполняется запрос?
– Используется индекс post_status=‘publish’
– Перебор почти всей таблицы для проверки остальных
условий
– Временная таблица (в памяти, если меньше
tmp_table_size), содержащая все поля таблиц, участвующих
в JOIN
– Cортировка всей временной таблицы (filesort, без
использования индексов)
– LIMIT 3,3 – оставляем записи с 4 по 6
III. ORDER BY + LIMIT (6/8)
• Решение: разбить запрос
•Сортировать только значения id
•Наложить ограничение LIMIT
•Получить значения остальных полей
• Схематическое решение:
• SELECT * FROM large_table WHERE id IN
• (SELECT id FROM large_table WHERE условие
• AND условие AND условие ORDER BY порядок LIMIT M,N)
ORDER BY порядок;
•  IN + LIMIT будет только в MySQL 6.0
III. ORDER BY + LIMIT (7/8)
•
•
•
•
•
•
•
•
•
•
•
Пример полного решения
CREATE TEMPORARY TABLE tmp_postid ENGINE=MEMORY
SELECT wp_posts.ID FROM wp_posts LEFT JOIN wp_post2cat ON
(wp_posts.ID = wp_post2cat.post_id)
WHERE (category_id = '1')
AND post_date_gmt <= '2008-09-12 00:15:59‘
AND (post_status = 'publish') AND post_status !=
'attachment‘
ORDER BY post_date DESC LIMIT 3, 3;
SELECT * FROM tmp_postid t JOIN wp_posts USING(ID)
LEFT JOIN wp_post2cat ON (wp_posts.ID =
wp_post2cat.post_id)
ORDER BY post_date DESC;
DROP TEMPORARY TABLE tmp_postid;
III. ORDER BY + LIMIT (8/8)
• Особенности решения
– Сортировать приходится дважды
• Можно обойти, сохраняя порядок в первом запросе
•
SET @order:=0; SELECT id, @order:=@order+1 AS ord ..
– SELECT превращается в INSERT+SELECT
• Временную таблицу можно создавать в другой базе данных, чтобы
избежать репликации или использовать SET
SQL_LOG_BIN:=0;
• При небольшом количестве записей список id можно собирать в
языке программирования или в переменной MySQL
IV. Безобидные подзапросы
• Три типа подзапросов
– В контексте выбираемых полей (обычно зависимый)
SELECT clients.id, (SELECT count(*) FROM
contracts WHERE contracts.client=clients.id)
FROM clients;
– В контексте FROM (независимый подзапрос)
SELECT * FROM clients,(SELECT a FROM b) AS stats;
– В условии WHERE (зависимый или независимый)
•
SELECT * FROM clients WHERE EXISTS(SELECT 1 FROM
contracts WHERE contracts.client=clients.id)
IV. Оптимизация подзапросов
• Мощный встроенный механизм оптимизации
появится в MySQL 6.0
• http://forge.mysql.com/wiki/Subquery_Works
• Зависимые подзапросы, если возможно,
преобразовывать в JOIN
• Некоторые независимые подзапросы
обрабатываются как зависимые
V. Механизмы хранения
• MyISAM
• InnoDB
• MEMORY
• ndbcluster
V. MyISAM
• Индекс и данные в отдельных файлах
– table.MYI файл ссылается на конкретные позиции в файле table.MYD
• Блокировки на уровне таблиц
– SELECT может устанавливать блокировку READ LOCAL,
разрешая запись в конец таблицы
SET GLOBAL concurrent_insert=x
• x=0, блокировка READ
• x=1, блокировка READ LOCAL, если нет щелей
• x=2, блокипрвка READ LOCAL в любом случае
V. MyISAM Key Cache
SHOW VARIABLES LIKE 'key_buffer_size';
SHOW STATUS LIKE 'key_blocks%';
V. Индивидуальный кэш индексов
• Установка
– SET GLOBAL hot_cache.key_buffer_size=128*1024;
• Загрузка индексов таблиц в кэш
CACHE INDEX t1, t2, t3 IN hot_cache;
+---------+--------------------+----------+----------+
| Table
| Op
| Msg_type | Msg_text |
+---------+--------------------+----------+----------+
| test.t1 | assign_to_keycache | status
| OK
|
| test.t2 | assign_to_keycache | status
| OK
|
| test.t3 | assign_to_keycache | status
| OK
|
+---------+--------------------+----------+----------+
V. InnoDB
• Поддержка транзакций (ACID)
• Блокировки на уровне строк
• innodb_flush_log_at_trx_commit
– 0 – сбрасывать логи на диск на каждой контрольной точке
(примерно раз в секунду)
– 1 – сбрасывать логи при завешении каждой транзакции
– 2 – сбрасывать логи при завершении каждой транзакции,
но fsync выполнять только на контрольной точке
V. Innodb buffer pool
Переменная innodb_buffer_pool_size
V. MEMORY
•+
• Хранение таблиц в памяти (до max_heap_table_size на таблицу, но
не больше 4 Гб)
• Быстрый доступ к данным
• Два типа индексов (HASH и BTREE)
•• Данные не сохраняются при остановке сервера
• Нельзя использовать BLOB/TEXT
• Все строки фиксированной длины, VARCHAR(4000) будет работать
как CHAR(4000)
V. MySQL Cluster
VI. Кэш запросов MySQL
VI. Кэш запросов MySQL
• Не зависит от механизма хранения
• Только буквально идентичные запросы
• Подзапросы не кэшируются отдельно
• Функции NOW(), RAND(), и др., пользовательские
переменные и хранимые функции отводят запрос от
кэша
• Включить кэш:
– query_cache_type=1 (значение 2 включает кэш по требованию)
– query_cache_size=128M
VI. Кэш запросов MySQL
• Любое изменение таблицы, удаляет из кэша все
запросы, использующие данную таблицу. Пример:
•
UPDATE articles
•
SET viewcount=viewcount+1
•
WHERE id=542;
•
•
Переносите счетчики в отдельные таблицы!
• Использованием кэша можно управлять:
– SELECT SQL_NO_CACHE …
– SELECT SQL_CACHE …
VII. Менять структуру данных?!
Учитывая вашу репутацию, я бы не
обратился к вам, если бы у меня был выбор.
- Из фильма «Револьвер»
-
-
• Очень серьезное изменение кода приложения
• У скольких присутствующих в зале, приложение
использует только инвариантные процедуры?
VII. (Де)?нормализация
• Нормализация – исключение избыточности в данных
• Денормализация – внесение избыточной информации
Inventory
sID
sLoc
sPostal
pID1
pName1
pQty1
pID2
pName2
pQty2
1
Holtsville
00501
1
bed
15
2
chair
4
2
3
4
Waukesha
Waukesha
Ketchikan
53146
53146
99950
1
2
2
bed
chair
chair
4
8
24
3
4
4
table
sofa
sofa
6
4
10
1NF
Inventory_1NF
sPostal
pID
sID
sLoc
pName
pQty
1
Holtsville
00501
1
bed
15
1
Holtsville
00501
2
chair
4
2
2
Waukesha
Waukesha
53146
53146
1
3
bed
table
4
6
3
3
4
Waukesha
Waukesha
Ketchikan
53146
53146
99950
2
4
2
chair
sofa
chair
8
4
24
4
Ketchikan
99950
4
sofa
10
VII. Третья нормальная форма
• Нет функциональной зависимости колонок, каждая
зависит только от первичногно ключа.
Part_3NF
Part_1NF
sID
1
1
pID
1
2
pName
bed
chair
pQty
15
4
2
2
1
3
bed
table
4
6
3
2
chair
8
3
4
4
4
2
4
sofa
chair
sofa
4
24
10
3NF
3NF
sID
1
1
2
pID
1
2
1
Qty
15
4
4
2
3
3
3
2
4
6
8
4
4
4
2
4
24
10
PartName_3NF
pID
pName
1
bed
2
chair
3
table
4
sofa
VII. Денормализация
• Выполните полную нормализацию перед тем, как
начинать денормализацию
• Избыточные поля в той же таблице
– ЗА
• Не потребуется JOIN
– Против
• Триггер не может изменять собственную таблицу
• UPDATE сбрасывает кэш запросов
VIII. Выводы. Оптимизация запросов
• Что делает запрос и как он будет выполняться?
(EXPLAIN поможет)
• Какие индексы он будет использовать?
• Как написать этот же запрос проще?
• Безобидны ли подзапросы?
• Будет ли запрос кэшироваться?
• Если ничего не помогает – оптимизируйте
структуру таблиц.
Заключение
• Лучше день потерять,
• потом за пять минут долететь.
•
•
Спасибо за внимание!
Пишите: rgbeast@sqlinfo.ru, http://sqlinfo.ru/forum/
Download