optimizando mysql
TRANSCRIPT
Optimizando MySQL
Marcelo AltmannTécnologo em Sistemas para Internet
MySQL DBA @ IEDR
Blogueiro - blog.marceloaltmann.com
Oracle ACE Associate - MySQL
Oracle Certified Professional , MySQL 5.6 Database Administrator
Oracle Certified Professional , MySQL 5 Database Administrator
Oracle Certified Professional , MySQL 5 Developer
Oracle Certified Associate , MySQL 5.0 / 5.1 / 5.5
Agenda> Overview
> Configuração
> Índices
> Tabelas temporárias
> Identificação de queries
Overview
Overview
Fonte: http://www.oracle.com/technetwork/articles/java/mysql-acq-139875.html
Configuração
Configuração - Innodb Buffer Pool
Configuração - Innodb Buffer Pool
Configuração - Innodb Buffer Pool
Configuração - Innodb Buffer Pool
Configuração - Innodb Buffer Pool● Monitorar: SHOW GLOBAL STATUS LIKE ‘Innodb_buffer_pool_read%’ :
○ Innodb_buffer_pool_reads - Leituras feitas direto no disco○ Innodb_buffer_pool_read_requests - Leituras feitas na memória
● Innodb_buffer_pool_size (Padrão: 128M)
● Innodb_buffer_pool_dump_at_shutdown
● innodb_buffer_pool_load_at_startup
Configuração - transaction log (redo log)
Configuração - transaction log (redo log)
Configuração - transaction log (redo log)
Configuração - transaction log (redo log)
Configuração - transaction log (redo log)● Monitorar: SHOW GLOBAL STATUS LIKE ‘Innodb_log_waits’
● Innodb_log_buffer_size
○ Padrão 8M - 5.5 / 5.6 / 5.7.5
○ Padrão 16M - 5.7.6
Configuração - transaction log (redo log)● Innodb_flush_log_at_trx_commit=1
● Padrão (ACID)
Configuração - transaction log (redo log)● Innodb_flush_log_at_trx_commit=1
● Padrão (ACID)
Configuração - transaction log (redo log)● Innodb_flush_log_at_trx_commit=1
● Padrão (ACID)
Configuração - transaction log (redo log)● Innodb_flush_log_at_trx_commit=1
● Padrão (ACID)
Configuração - transaction log (redo log)● Innodb_flush_log_at_trx_commit=1
● Padrão (ACID)
Configuração - transaction log (redo log)● Innodb_flush_log_at_trx_commit=0
Configuração - transaction log (redo log)● Innodb_flush_log_at_trx_commit=0
Configuração - transaction log (redo log)● Innodb_flush_log_at_trx_commit=0
Configuração - transaction log (redo log)● Innodb_flush_log_at_trx_commit=2
Configuração - transaction log (redo log)● Innodb_flush_log_at_trx_commit=2
Configuração - transaction log (redo log)● Innodb_flush_log_at_trx_commit=2
Configuração - transaction log (redo log)● Innodb_flush_log_at_trx_commit=2
Índices
Índices - Full table scanCREATE TABLE `city` ( `ID` int(11) NOT NULL AUTO_INCREMENT, `Name` char(35) NOT NULL DEFAULT '', `CountryCode` char(3) NOT NULL DEFAULT '', `District` char(20) NOT NULL DEFAULT '', `Population` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`ID`)) ENGINE=InnoDB AUTO_INCREMENT=4080 DEFAULT CHARSET=latin1;
Índices - Full table scan
mysql> EXPLAIN SELECT Name, Population FROM city WHERE CountryCode='BRA' AND Population > 1000000\G*************************** 1. row *************************** id: 1 select_type: SIMPLE table: city type: ALLpossible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 4188 Extra: Using where1 row in set (0.00 sec)
Índices - Full table scan
mysql> EXPLAIN SELECT Name, Population FROM city WHERE CountryCode='BRA' AND Population > 1000000\G*************************** 1. row *************************** id: 1 select_type: SIMPLE table: city type: ALLpossible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 4188 Extra: Using where1 row in set (0.00 sec)
Índices - Left most partALTER TABLE city ADD KEY leftMost(CountryCode, Population, District);
mysql> EXPLAIN SELECT Name, Population FROM city WHERE CountryCode='BRA' AND Population > 1000000\G*************************** 1. row *************************** id: 1 select_type: SIMPLE table: city type: rangepossible_keys: leftMost key: leftMost key_len: 7 ref: NULL rows: 13 Extra: Using index condition1 row in set (0.00 sec)
Índices - Left most partALTER TABLE city ADD KEY leftMost(CountryCode, Population, District);
mysql> EXPLAIN SELECT Name, Population FROM city WHERE CountryCode='BRA' AND Population > 1000000\G*************************** 1. row *************************** id: 1 select_type: SIMPLE table: city type: rangepossible_keys: leftMost key: leftMost key_len: 7 ref: NULL rows: 13 Extra: Using index condition1 row in set (0.00 sec)
Índices - Left most partmysql> EXPLAIN FORMAT=JSON SELECT Name, Population FROM city WHERE CountryCode='BRA' AND Population > 1000000;{ "query_block": { "select_id": 1, "table": { "table_name": "city", "access_type": "range", "possible_keys": [ "CountryCode" ], "key": "CountryCode", "used_key_parts": [ "CountryCode", "Population" ], "key_length": "7", "rows": 13, "filtered": 100, "index_condition": "((`world`.`city`.`CountryCode` = 'BRA') and (`world`.`city`.`Population` > 1000000))" } }}
Índices - Covered indexALTER TABLE city ADD KEY covered (CountryCode, Population, Name);
mysql> EXPLAIN SELECT Name, Population FROM city WHERE CountryCode='BRA' AND Population > 1000000\G*************************** 1. row *************************** id: 1 select_type: SIMPLE table: city type: rangepossible_keys: covered key: covered key_len: 7 ref: NULL rows: 13 Extra: Using where; Using index1 row in set (0.00 sec)
Índices - Covered indexALTER TABLE city ADD KEY covered (CountryCode, Population, Name);
mysql> EXPLAIN SELECT Name, Population FROM city WHERE CountryCode='BRA' AND Population > 1000000\G*************************** 1. row *************************** id: 1 select_type: SIMPLE table: city type: rangepossible_keys: covered key: covered key_len: 7 ref: NULL rows: 13 Extra: Using where; Using index1 row in set (0.00 sec)
Tabelas temporárias
Tabelas temporárias● GROUP BY
● UNION
● SUBQUERY + WHERE
● Memória: Memory Engine
● Disco:
○ 5.6 - MyIsam Engine
○ 5.7 - Innodb Engine
● Memory Engine:
○ Não tem suporte a campos BLOB / TEXT
● https://dev.mysql.com/doc/refman/5.6/en/internal-temporary-tables.html
Tabelas temporárias● tmp_table_size - tamanho máximo de uma tabela temporária● max_head_table_size - tamanho máximo de uma tabela que utiliza memory engine
● Tamanho tabela temporária:
○ Maior que tmp_table_size ou max_head_table_size = criada em disco● Monitorar:
mysql> SHOW GLOBAL STATUS LIKE 'Created\_tmp%tables';
+-------------------------+-------+
| Variable_name | Value |
+-------------------------+-------+
| Created_tmp_disk_tables | 3 |
| Created_tmp_tables | 17 |
+-------------------------+-------+
Identificação de queries
Identificação de queries● SHOW [FULL] PROCESSLIST
● Slow query log
● performance_schema.events_statements_summary_by_digest
Identificação de queries - Processlist
● Mostra as conexões atuais e seus statusmysql> show processlist;+----+------+-----------+-----------+---------+------+----------------+--------------------------------------------------------------------------------------------------+| Id | User | Host | db | Command | Time | State | Info |+----+------+-----------+-----------+---------+------+----------------+--------------------------------------------------------------------------------------------------+| 8 | root | localhost | employees | Query | 4 | Writing to net | SELECT MAX(salary) FROM salaries JOIN employees USING(emp_no) WHERE gender = 'M' GROUP BY emp_no || 9 | root | localhost | employees | Query | 0 | init | show processlist |+----+------+-----------+-----------+---------+------+----------------+--------------------------------------------------------------------------------------------------+2 rows in set (0.00 sec)
Identificação de queries - Slow Query
● Slow_query_log
● Long_query_time = N
Identificação de queries - Slow Query# Time: 160908 17:38:01# User@Host: root[root] @ localhost [] Id: 2# Query_time: 1.127100 Lock_time: 0.000852 Rows_sent: 1000 Rows_examined: 297918use employees;SET timestamp=1473370681;SELECT d.dept_name AS 'Dept', CONCAT(em.last_name, ' ', em.first_name) AS 'Manager last, first', CONCAT(e.last_name,' ', e.first_name, ' ', t.title) AS 'Employee last, first (title)' FROM dept_manager AS dm LEFT JOIN dept_emp AS de ON de.dept_no = dm.dept_no LEFT JOIN departments AS d ON d.dept_no = dm.dept_no LEFT JOIN employees AS e ON e.emp_no = de.emp_no LEFT JOIN employees AS em ON em.emp_no = dm.emp_no LEFT JOIN titles AS t ON t.emp_no = e.emp_no WHERE dm.emp_no = e.emp_no AND dept_name = 'Sales' OR dept_name = 'Marketing' AND dm.to_date >= '2012-05-07' AND t.to_date > '2012-05-07' AND de.to_date > '2012-05-07' ORDER BY e.last_name, e.first_name limit 1000;# Time: 160908 17:38:27# User@Host: root[root] @ localhost [] Id: 2# Query_time: 4.236115 Lock_time: 0.000377 Rows_sent: 179973 Rows_examined: 2366291SET timestamp=1473370707;SELECT MAX(salary) FROM salaries JOIN employees USING(emp_no) WHERE gender = 'M' GROUP BY emp_no;# Time: 160908 17:38:33# User@Host: root[root] @ localhost [] Id: 2# Query_time: 3.268998 Lock_time: 0.000349 Rows_sent: 179973 Rows_examined: 2366291SET timestamp=1473370713;SELECT MAX(salary) FROM salaries JOIN employees USING(emp_no) WHERE gender = 'M' GROUP BY emp_no;
Identificação de queries - performance schema
● Ativado por padrão desde a versão 5.6.6
● DIGEST:○ SELECT Name, Population FROM city WHERE CountryCode='BRA' AND Population >
1000000;○ SELECT Name, Population FROM city WHERE CountryCode='USA' AND Population >
5000000;○ SELECT Name , Population FROM city WHERE CountryCode = ? AND Population > ?;
● Possibilita identificar queries :○ Não utilizam index:
SELECT DIGEST_TEXT FROM events_statements_summary_by_digest WHERE SUM_NO_INDEX_USED > 0;
○ Usam tabelas temporárias no disco:SELECT DIGEST_TEXT FROM events_statements_summary_by_digest WHERE
SUM_CREATED_TMP_DISK_TABLES > 0;
Perguntas ?
Perguntas ?● https://groups.google.com/group/mysqlbr
● @altmannmarcelo
● pt.planet.mysql.com
● Forum em português - http://forums.mysql.com/list.php?72