sexta-feira, 2 de maio de 2014

Índice de referência MySQL com mysqlslap

Original post: http://anothermysqldba.blogspot.com/2014/05/mysql-benchmark-with-mysqlslap.html

Então aferição diferentes consultas MySQL contra seu banco de dados é uma coisa sensata a fazer. Isso deveria ser óbvio. Enquanto otimizar consultas o melhor que podemos usar EXPLAIN (e explicar ESTENDIDO), tendo-lhes tempo para referência deles deve ser útil. 

Este é um exemplo simples de executar uma instrução mysqlslap. 

Para este exemplo eu carreguei o banco de dados do MySQL MUNDO. (http://dev.mysql.com/doc/index-other.html ) 

Eu criei uma consulta que juntou todas as três tabelas e colocá-lo em / tmp / tests.sql. O plano de explicar é abaixo. 

root@localhost [world]> EXPLAIN EXTENDED SELECT C.Name as City, Y.Name as Country, L.Language,Y.Population FROM City C INNER JOIN Country Y ON C.CountryCode = Y.Code INNER JOIN CountryLanguage L ON C.CountryCode = L.CountryCode WHERE C.Name LIKE 'D%' AND Y.Continent='Europe' \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: C
type: range
possible_keys: CountryCode,name_key
key: name_key
key_len: 5
ref: NULL
rows: 127
filtered: 100.00
Extra: Using where
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: Y
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 3
ref: world.C.CountryCode
rows: 1
filtered: 100.00
Extra: Using where
*************************** 3. row ***************************
id: 1
select_type: SIMPLE
table: L
type: ref
possible_keys: PRIMARY,CountryCode
key: CountryCode
key_len: 3
ref: world.C.CountryCode
rows: 2
filtered: 100.00
Extra: Using index
3 rows in set, 1 warning (0.00 sec)

root@localhost [world]> show warnings \G
*************************** 1. row ***************************
Level: Note
Code: 1003
Message: /* select#1 */ select `world`.`C`.`Name` AS `City`,`world`.`Y`.`Name` AS `Country`,`world`.`L`.`Language` AS `Language`,`world`.`Y`.`Population` AS `Population` from `world`.`City` `C` join `world`.`Country` `Y` join `world`.`CountryLanguage` `L` where ((`world`.`Y`.`Code` = `world`.`C`.`CountryCode`) and (`world`.`L`.`CountryCode` = `world`.`C`.`CountryCode`) and (`world`.`Y`.`Continent` = 'Europe') and (`world`.`C`.`Name` like 'D%'))


Agora, a ferramenta mysqlslap tem sido em torno desde o MySQL 5.1.4 
Abaixo estão alguns outros links úteis. 
Agora que eu tenho a minha consulta, eu posso aferir isso no banco de dados com o seguinte comando. 

mysqlslap - simultaneidade = 150 - iterações = 50 - query = / tmp / test.sql - criar-schema = mundo 

Uma nota: 
A consulta tem que ser muito limpo, a ferramenta faz erro facilmente. 
Por exemplo, o seguinte jogou este erro: 

SELECT C.Name as City, Y.Name as Country, L.Language,Y.Population
FROM City C
INNER JOIN Country Y ON C.CountryCode = Y.Code
INNER JOIN CountryLanguage L ON C.CountryCode = L.CountryCode
WHERE C.Name LIKE 'D%' AND Y.Continent='Europe' 

Enquanto esta consulta funcionou muito bem. 

SELECT C.Name as City, Y.Name as Country, L.Language,Y.Population FROM City C INNER JOIN Country Y ON C.CountryCode = Y.Code INNER JOIN CountryLanguage L ON C.CountryCode = L.CountryCode WHERE C.Name LIKE 'D%' AND Y.Continent='Europe' 


A ferramenta resultados de benchmark saída para você 


Benchmark
Average number of seconds to run all queries: 0.104 seconds
Minimum number of seconds to run all queries: 0.096 seconds
Maximum number of seconds to run all queries: 0.141 seconds
Number of clients running queries: 150
Average number of queries per client: 1 


mysqlslap - help lhe dará várias opções para testar suas consultas com. 

Você pode fazer tudo automaticamente 

# mysqlslap --auto-generate-sql
Benchmark
Average number of seconds to run all queries: 0.243 seconds
Minimum number of seconds to run all queries: 0.243 seconds
Maximum number of seconds to run all queries: 0.243 seconds
Number of clients running queries: 1
Average number of queries per client: 0 


Você pode testar inserções também. Por exemplo, eu criei esta tabela: 

CREATE TABLE `foobar_table` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`time_recorded` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB ; 


Então, em seguida, testado com o seguinte. 

# mysqlslap --concurrency=1150 --iterations=530 --query="use test;insert into foobar_table (id) values (null)" --delimiter=";"
mysqlslap: Could not create thread 


Erros OK não são muito úteis ... Mas espero que você percebe o erro. É difícil ter 1.150 transações simultâneas se você tiver apenas 530 iterações. 


# mysqlslap --concurrency=150 --iterations=30 --query=/tmp/test1.sql --create-schema=test --verbose
Benchmark
Average number of seconds to run all queries: 0.260 seconds
Minimum number of seconds to run all queries: 0.192 seconds
Maximum number of seconds to run all queries: 0.476 seconds
Number of clients running queries: 150
Average number of queries per client: 1


Por exemplo, o seguinte funcionou muito melhor. 

# mysqlslap --concurrency=200 --iterations=1000 --query=" insert into foobar_table (id) values (null)" --verbose --create-schema=test
Benchmark
Average number of seconds to run all queries: 0.282 seconds
Minimum number of seconds to run all queries: 0.217 seconds
Maximum number of seconds to run all queries: 0.726 seconds
Number of clients running queries: 200
Average number of queries per client: 1 


Só para provar que estamos fazendo inserções reais .. 

root@localhost [test]> select count(id) from foobar_table;
+-----------+
| count(id) |
+-----------+
| 206091 |
+-----------+
1 row in set (0.13 sec) 

Agora eu também devo dizer que este é apenas um banco de dados de teste que eu uso para postagens no blog, por isso não avaliar seus bancos de dados de produção contra esses resultados. 

Acho que o ponto depois de tudo isso ... encontrar uma consulta problemático, otimizá-lo o melhor que puder, e referência-lo. É melhor conhecer os seus limites, em vez de apenas um palpite.