gracetory’s blog

東池袋にある合同会社グレストリのエンジニアブログです

MySQLのmysqlslapを使ってみた

f:id:grshizawa:20200129182237j:plain

はじめに

今回はMySQLのmysqlslapを使用する機会があったので、備忘録程度に残しておきたいと思います。
初めて使ったので、不明なことも多々ありますが、諸々試した結果を記載していきます。

mysqlslapとは

MySQLが公式でサポートしている、負荷エミュレーションツール。
複数のクライアントが並列でSQLを発行しているかのように、負荷テストを行うことができる。
MySQLをインストールすると、デフォルトでインストールされる。

基本的にはコマンドラインから行い、オプションによって、並列クライアント数や試行回数、
発行するSQL内容を決めることができる。
自動的にSQLを生成することもでき、このパターンをコマンドから指定できる。

実行してみる

※MySQLバージョン : 5.7.21

※引数については公式ドキュメントを参照、引用しています。
https://dev.mysql.com/doc/refman/5.6/ja/mysqlslap.html

テスト用のDB、テーブルを一時的に作成して自動生成したSQLを実行する

使用する引数

引数備考
--user
--password
--host
--port
--engine
データベース接続情報
--create-schema テストを実行するスキーマ
--auto-generate-sql SQL ステートメントがファイルおよびコマンドオプションを使用して指定されない場合、自動的に生成
--no-dropテスト実行中に作成されたスキーマを削除しない
--only-print データベースに接続せずにDBに実行するであろうSQLの出力のみを行います。

--auto-generate-sqlを指定するとスキーマ、テーブルが自動で作成されてSQLも自動で生成して実行されるようです。
挙動をみてみます。

実行コマンド

/usr/local/mysql/bin/mysqlslap --user=user --password=password --host=localhost --port=3306 --engine=innodb --create-schema=sinki_db --no-drop --auto-generate-sql

実行結果

Benchmark
    Running for engine innodb
    Average number of seconds to run all queries: 0.015 seconds → 平均実行時間(試行回数に対する)
    Minimum number of seconds to run all queries: 0.015 seconds → 最小実行時間
    Maximum number of seconds to run all queries: 0.015 seconds → 最大実行時間
    Number of clients running queries: 1                                                → クライアントの数
    Average number of queries per client: 0                                         → 1クライアントが発行したSQLの数

Average number of queries per clientが0になっているのは?自動生成するSQLはカウントされない?

DBを確認
とりあえず、mysqlに接続して何かレコードが作成されているのか、DBの中身を確認してみます。

mysql> show databases;
+-----------------------+
| Database                        |
+-----------------------+
| sinki_db                          |
+-----------------------+

--create-schemaに指定した「sinki_db」が作成されています。

作成されたテーブルを見てみると

mysql> use sinki_db;
Database changed
mysql> show tables;
+--------------------+
| Tables_in_sinki_db |
+--------------------+
| t1                           |
+--------------------+

「t1」という名前でテーブルが作成されています。

テーブルの中身を見てみると

mysql> select * from t1;
+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| intcol1    | charcol1                                                                                                                                                                                                                                                                                     |
+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 1804289383 | mxvtvmC9127qJNm06sGB8R92q2j7vTiiITRDGXM9ZLzkdekbWtmXKwZ2qG1llkRw5m9DHOFilEREk3q7oce8O3BEJC0woJsm6uzFAEynLH2xCsw1KQ1lT4zg9rdxBL      |
|  822890675 | 97RGHZ65mNzkSrYT3zWoSbg9cNePQr1bzSk81qDgE4Oanw3rnPfGsBHSbnu1evTdFDe83ro9w4jjteQg4yoo9xHck3WNqzs54W5zEm92ikdRF48B2oz3m8gMBAl11W  |
            ・
            ・
            ・
|  364531492 | qMa5SuKo4M5OM7ldvisSc6WK9rsG9E8sSixocHdgfa5uiiNTGFxkDJ4EAwWC2e4NL1BpAgWiFRcp1zIH6F1BayPdmwphatwnmzdwgzWnQ6SRxmcvtd6JRYwEKdvuWr   |
+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
105 rows in set (0.00 sec)

intcol1、charcol1というカラムに、ランダムな値がインサートされていました。(105件)。
これだけではテーブル作成とINSERTされていることしか分からないですね。

実行コマンドに「--only-print」引数を付け足すと、実行しているSQLを確認できるみたいなので、実行してみます。

CREATE SCHEMA `sinki_db`;
use sinki_db;
set default_storage_engine=`innodb`;
CREATE TABLE `t1` (intcol1 INT(32) ,charcol1 VARCHAR(128));
INSERT INTO t1 VALUES (1804289383,'mxvtvmC9127qJNm06sGB8R92q2j7vTiiITRDGXM9ZLzkdekbWtmXKwZ2qG1llkRw5m9DHOFilEREk3q7oce8O3BEJC0woJsm6uzFAEynLH2xCsw1KQ1lT4zg9rdxBL');
INSERT INTO t1 VALUES (822890675,'97RGHZ65mNzkSrYT3zWoSbg9cNePQr1bzSk81qDgE4Oanw3rnPfGsBHSbnu1evTdFDe83ro9w4jjteQg4yoo9xHck3WNqzs54W5zEm92ikdRF48B2oz3m8gMBAl11W');
INSERT INTO t1 VALUES (1308044878,'50w46i58Giekxik0cYzfA8BZBLADEg3JhzGfZDoqvQQk0Akcic7lcJInYSsf9wqin6LDC1vzJLkJXKn5onqOy04MTw1WksCYqPl2Jg2eteqOqTLfGCvE4zTZwWvgMz');
INSERT INTO t1 VALUES (964445884,'DPh7kD1E6f4MMQk1ioopsoIIcoD83DD8Wu7689K6oHTAjD3Hts6lYGv8x9G0EL0k87q8G2ExJjz2o3KhnIJBbEJYFROTpO5pNvxgyBT9nSCbNO9AiKL9QYhi0x3hL9');
INSERT INTO t1 VALUES (1586903190,'lwRHuWm4HE8leYmg66uGYIp6AnAr0BDd7YmuvYqCfqp9EbhKZRSymA4wx6gpHlJHI53DetH9j7Ixar90Jey5outd1ZIAJdJTjMaD7rMiqYXHFhHaB7Xr1HKuqe51GG');
INSERT INTO t1 VALUES (962033002,'rfw4egILWisfxPwOc3nJx4frnAwgI539kr5EXFbupSZelM2MHqZEmD6ZNuEZzHib8fqYuHQbdrDND8lXqIdcNbAeWOBLZlpZOX5AoNlQFzpK7QjxcLP0wbWIriYGJL');
INSERT INTO t1 VALUES (1910858270,'ksnug3YyANnWWDEJiRkiFC4a3e6KyJ2i3hSjksiuFLHlRXw9yhjDtnfoQd0OouyrcIbCB9zQWG4pf0yTZhaIT67nj7BY21FWJqaWrZxEh13Kt2hRbGl4MsrxsuLmvd');
INSERT INTO t1 VALUES (63299708,'FJid3GaHpRC2L6jgirPm5AW3uGGgCloJ5Ww0eNHSiLWvS5bAxto23AxxR6TXr9qofeoAtxWcJsXnxzxmsdhvoekFc5mSES8tyxvsuPK5Hjs7ihtaJaLz5xEh2s1GCA');
INSERT INTO t1 VALUES (737703662,'2zxutF6rOqjXYHHzSrKRwAhWCPXTdhNXYKQIRO9sEkFf1YeTGqw40Ta5u6QNfpvC1DWTTXDkFSFHtte9bbDSwgZjmryHglLhqjAKEF4MkJfT49eXcjzZNOG1F6BnsY');
INSERT INTO t1 VALUES (1348361729,'i8X2EnycNH7sDHMltxcILtQE0ZPoPq9zyg24J0hiAgQNpg8jedtrWK5WtXIALR9B03FJ4ou6TCTAtWtN7fETzBzkiAmvTv6LrEZn2RtNfMaOkJfjytCp54ZfEJbb7Z');
-- ここまでの10件が以下繰り返しINSERT
INSERT INTO t1 VALUES (1804289383,'mxvtvmC9127qJNm06sGB8R92q2j7vTiiITRDGXM9ZLzkdekbWtmXKwZ2qG1llkRw5m9DHOFilEREk3q7oce8O3BEJC0woJsm6uzFAEynLH2xCsw1KQ1lT4zg9rdxBL');
INSERT INTO t1 VALUES (822890675,'97RGHZ65mNzkSrYT3zWoSbg9cNePQr1bzSk81qDgE4Oanw3rnPfGsBHSbnu1evTdFDe83ro9w4jjteQg4yoo9xHck3WNqzs54W5zEm92ikdRF48B2oz3m8gMBAl11W');
INSERT INTO t1 VALUES (1308044878,'50w46i58Giekxik0cYzfA8BZBLADEg3JhzGfZDoqvQQk0Akcic7lcJInYSsf9wqin6LDC1vzJLkJXKn5onqOy04MTw1WksCYqPl2Jg2eteqOqTLfGCvE4zTZwWvgMz');
  ・
  ・
  ・
-- ここまで100件のINSERT
INSERT INTO t1 VALUES (100669,'qnMdipW5KkXdTjGCh2PNzLoeR0527frpQDQ8uw67Ydk1K06uuNHtkxYBxT5w8plb2BbpzhwYBgPNYX9RmICWGkZD6fAESvhMzH3yqzMtXoH4BQNylbK1CmEIPGYlC6');
SELECT intcol1,charcol1 FROM t1;
INSERT INTO t1 VALUES (73673339,'BN3152Gza4GW7atxJKACYwJqDbFynLxqc0kh30YTwgz3FktQ43XTrqJ4PQ25frn7kXhfXD8RuzN1j8Rf3y8ugKy6es3IbqPJM6ylCyD6xS7YcQCfHKZxYNvB7yTahm');
SELECT intcol1,charcol1 FROM t1;
INSERT INTO t1 VALUES (1759592334,'3lkoxjtvgLu5xKHSTTtJuGE5F5QqmCcppCTmvFZScRZQgim93gSxwb24gKmIPEzEQStMjQiCu7WapGbkw4ilXch3xRLMhKSzgLDOovSi2qGj6rKvnuYAWDDJgaZDu2');
SELECT intcol1,charcol1 FROM t1;
INSERT INTO t1 VALUES (95275444,'bNIrBDBl81tjzdvuOpQRCXgX37xGtzLKEXBIcE3k7xK7aFtqxC99jqYnpTviK83bf6lGDgsKd4R3KLmHPnI8TqnIKj1gjw7N2sXFZNS2Svyg8cpZN7atxL39w4igsp');
SELECT intcol1,charcol1 FROM t1;
INSERT INTO t1 VALUES (866596855,'naQuzhMt1IrZIJMkbLAKBNNKKK2sCknzI5uHeGAgQuDd5SLgpN0smODyc7qorTo1QaI5qLl97qmCIzl0Mds81x7TxpIoJyqlY0iEDRNKA1PS0AKEn5NhuMAr3KgEIM');
SELECT intcol1,charcol1 FROM t1;
INSERT INTO t1 VALUES (364531492,'qMa5SuKo4M5OM7ldvisSc6WK9rsG9E8sSixocHdgfa5uiiNTGFxkDJ4EAwWC2e4NL1BpAgWiFRcp1zIH6F1BayPdmwphatwnmzdwgzWnQ6SRxmcvtd6JRYwEKdvuWr');

 
出力内容をみてみると
・スキーマ、テーブル作成(CREATE TABLE t1 (intcol1 INT(32) ,charcol1 VARCHAR(128));)
・10レコード × 10回をインサート。
・レコードのINSERT、テーブルのSELECTを5回セット。
を実行しているようです。

 
引数を公式サイトで確認してみる
https://dev.mysql.com/doc/refman/5.6/ja/mysqlslap.html
・--auto-generate-sql-write-numberで各スレッドで実行する行挿入の回数を指定できる。
・--auto-generate-sql-load-type=にタイプ(mixed、read、write など)を指定すると、
 自動生成されるSQLを半分SELECT、半分INSERTとかSELECTだけなどの指定ができる。 など、 こんな感じで自動生成する内容を引数で制御できるようです。

 
注意点
※--auto-generate-sqlを使用する場合は「--no-drop」を引数に指定しないとdatabaseはテスト後に削除されてしまうので、既存のDBを使う場合は注意。
※--create-schemaに指定している名前DBがすでに存在していると、コマンド実行時にエラーとなる。

 

既存のDBのテーブルを使用し、並列クライアント数:5、試行回数:3回で指定したSQLを実行する。

使用する引数

引数備考
--user
--password
--host
--port
--engine
データベース接続情報
--create-schema テストを実行するスキーマ
--queryデータ取得のために使用するSELECT ステートメントを含む文字列(SQLを記述したファイルも指定できる)
--concurrencyシミュレートするクライアントの数
--iterations実行するテストの回数
--only-print データベースに接続せずにDBに実行するであろうSQLの出力のみを行います。

今度は先ほど作成したsinki_dbに対して指定したSQL文を実行してみます。

/usr/local/mysql/bin/mysqlslap --user=user --password=password --host=localhost --port=3306 --engine=innodb --create-schema=sinki_db 
--query="SELECT * FROM t1 ORDER BY intcol1 DESC" --concurrency=5 --iterations=3

※コマンドに「--auto-generate-sql」を指定している場合、デフォルトで「--create-schema」に指定したDBが削除されます。 今回は「--auto-generate-sql」を指定していないので、「--no-drop」はつけなくても削除されません。

5つのクライアントが下記SQLを3回実行する内容になっています。

SELECT * FROM t1 ORDER BY intcol1 DESC;  

実行結果

Benchmark
    Running for engine innodb
    Average number of seconds to run all queries: 0.010 seconds → 平均実行時間(試行回数3回の)
    Minimum number of seconds to run all queries: 0.008 seconds → 最小実行時間(試行回数3回の内)
    Maximum number of seconds to run all queries: 0.014 seconds → 最大実行時間(試行回数3回の内)
    Number of clients running queries: 5                                                → クライアントの数
    Average number of queries per client: 1                                         → 1クライアントが発行したSQLの数

DBを確認すると

mysql> select * from t1;

+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| intcol1    | charcol1                                                                                                                                                                                                                                                                                     |
+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 1804289383 | mxvtvmC9127qJNm06sGB8R92q2j7vTiiITRDGXM9ZLzkdekbWtmXKwZ2qG1llkRw5m9DHOFilEREk3q7oce8O3BEJC0woJsm6uzFAEynLH2xCsw1KQ1lT4zg9rdxBL      |
|  822890675 | 97RGHZ65mNzkSrYT3zWoSbg9cNePQr1bzSk81qDgE4Oanw3rnPfGsBHSbnu1evTdFDe83ro9w4jjteQg4yoo9xHck3WNqzs54W5zEm92ikdRF48B2oz3m8gMBAl11W  |
            ・
            ・
            ・
|  364531492 | qMa5SuKo4M5OM7ldvisSc6WK9rsG9E8sSixocHdgfa5uiiNTGFxkDJ4EAwWC2e4NL1BpAgWiFRcp1zIH6F1BayPdmwphatwnmzdwgzWnQ6SRxmcvtd6JRYwEKdvuWr   |
+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
105 rows in set (0.00 sec)

SELECT文を実行しただけなので、もちろんテーブルの内容は変化なし。

「--only-print」引数を付け足して、実行しているSQLを見てみます。

SELECT * FROM t1 ORDER BY intcol1 DESC;
SELECT * FROM t1 ORDER BY intcol1 DESC;
SELECT * FROM t1 ORDER BY intcol1 DESC;
SELECT * FROM t1 ORDER BY intcol1 DESC;
SELECT * FROM t1 ORDER BY intcol1 DESC;
SELECT * FROM t1 ORDER BY intcol1 DESC;
SELECT * FROM t1 ORDER BY intcol1 DESC;
SELECT * FROM t1 ORDER BY intcol1 DESC;
SELECT * FROM t1 ORDER BY intcol1 DESC;
SELECT * FROM t1 ORDER BY intcol1 DESC;
SELECT * FROM t1 ORDER BY intcol1 DESC;
SELECT * FROM t1 ORDER BY intcol1 DESC;
SELECT * FROM t1 ORDER BY intcol1 DESC;
SELECT * FROM t1 ORDER BY intcol1 DESC;
SELECT * FROM t1 ORDER BY intcol1 DESC;
(15回分のSQL)

--queryに指定したSQLを「クライアント数(5) × 試行回数(3) = 15回分」シミュレートしていることが分かりました。

実際にSELECT されているのかDBのプロセスリストを確認

(SQL実行中に確認)
mysql> SHOW FULL PROCESSLIST\G;
  ・
  ・
  ・
*************************** 7. row ***************************
     Id: 244266
   User: user
   Host: localhost
     db: sinki_db
Command: Query
   Time: 0
  State: Creating sort index
   Info: SELECT * FROM t1 ORDER BY intcol1 DESC

sinki_dbに対して、SELECT SQLが実行されていますね。

終わり

まだ基本的なことしかしていませんが、引数にあれこれ指定すれば
様々なSQLでDBのスペックテスト、SQLの速度テストなどができそうです。

導入の際に特に難しい設定をする必要もなく、気軽に試せるのがいいところですね。

まだ不明な点がたくさんあるので、また解決次第ブログに書いていきたいと思います。