Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Optimizando MySQL

Optimizando MySQL

Slides da palestra realizada no Dia da Liberdade do Software 2016. Esta palestra mostra algumas maneiras de se obter mais performance com o banco de dados MySQL.

Avatar for Marcelo Altmann

Marcelo Altmann

September 24, 2016
Tweet

More Decks by Marcelo Altmann

Other Decks in Technology

Transcript

  1. Marcelo Altmann Té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
  2. 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
  3. 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
  4. Índices - Full table scan CREATE 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;
  5. Í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: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 4188 Extra: Using where 1 row in set (0.00 sec)
  6. Í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: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 4188 Extra: Using where 1 row in set (0.00 sec)
  7. Índices - Left most part ALTER 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: range possible_keys: leftMost key: leftMost key_len: 7 ref: NULL rows: 13 Extra: Using index condition 1 row in set (0.00 sec)
  8. Índices - Left most part ALTER 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: range possible_keys: leftMost key: leftMost key_len: 7 ref: NULL rows: 13 Extra: Using index condition 1 row in set (0.00 sec)
  9. Índices - Left most part mysql> 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))" } } }
  10. Índices - Covered index ALTER 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: range possible_keys: covered key: covered key_len: 7 ref: NULL rows: 13 Extra: Using where; Using index 1 row in set (0.00 sec)
  11. Índices - Covered index ALTER 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: range possible_keys: covered key: covered key_len: 7 ref: NULL rows: 13 Extra: Using where; Using index 1 row in set (0.00 sec)
  12. 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
  13. 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 | +-------------------------+-------+
  14. Identificação de queries • SHOW [FULL] PROCESSLIST • Slow query

    log • performance_schema.events_statements_summary_by_digest
  15. Identificação de queries - Processlist • Mostra as conexões atuais

    e seus status mysql> 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)
  16. 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: 297918 use 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: 2366291 SET 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: 2366291 SET timestamp=1473370713; SELECT MAX(salary) FROM salaries JOIN employees USING(emp_no) WHERE gender = 'M' GROUP BY emp_no;
  17. 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;