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.

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;