Perl
MySQL

MySQLにData::Generator::FromDDLで大量のダミーデータを入れる方法

More than 3 years have passed since last update.

経緯

MySQLのチューニングのため、大量のデータを入れてパフォーマンスを計測する作業が必要となった。

Data::Generator::FromDDLというPerlライブラリがあるので、それを使ってダミーデータを入れることにした。 https://github.com/addsict/Data-Generator-FromDDL

手順

MySQLのmydbデータベースに、すでにcreate tableされているとする。まず、MySQLに付属しているmysqldumpというツールを使って、すでにmydbに作られたテーブルを再現してcreate tableするだけのSQL文であるDDLを取得する。

$ mysqldump -u katryo -p --no-data mydb > dump.sql

で、dump.sqlというDDLを生成する。

で、Data::Generator::FromDDLをシェルから扱えるdatagen_from_ddlを使って、

$ datagen_from_ddl --num=100000 dump.sql | mysql -u katryo -p mydb 

すると、MySQL内のmydbの各テーブルに、100000レコード/1テーブル のデータが入る。

8GBのMacBookAirで、26テーブルで100000レコードで実行すると30秒かかった。

Data::Generator::FromDDLの素晴らしさ

Data::Generator::FromDDLは、DDLをパースして自動的にダミーデータのinsert文を出力してくれる。

さきほどの例を、3レコード/1テーブルで行ってみよう。出力を見やすくするために --pretty のオプションもつけてみる。

$ datagen_from_ddl --num=3 --pretty dump.sql

をすると、以下のような文が出力される。ちなみに、レシピサイトを作っているとする。

INSERT IGNORE INTO `foodstuffs` (`foodstuff_id`,`name`,`created_at`) VALUES (1,'name1',-1429218243),(2,'name2',99576727),(3,'name3',-1565718941);
INSERT IGNORE INTO `request_ids` (`request_id`) VALUES (1),(2),(3);
INSERT IGNORE INTO `tags` (`tag_id`,`name`,`created_at`) VALUES (1,'name1',2542618628),(2,'name2',3291009850),(3,'name3',1095817358);
INSERT IGNORE INTO `users` (`user_id`,`nickname`,`family_name`,`given_name`,`email`,`salt_hashed_password`,`gender`,`created_at`,`updated_at`) VALUES (1,'nickname1','family_name1','given_name1','email1','salt_hashed_password1',-22,2261241673,2135291890),(2,'nickname2','family_name2','given_name2','email2','salt_hashed_password2',114,2162413120,440265079),

...(以下略)

こんな風に、create table文から、適当な値を入れてinsert文を作ってくれる。テーブル同士の関係、制約を守りながら大量のデータを入れるのに便利。

テーブルごとに入れるレコードの数を変えるとき

現実のアプリケーションでは、テーブルごとにレコード数はかなり異なる。なので、ダミーデータもテーブルごとの目的にあわせて、その量を変えるべきだ。Data::Generator::FromDDLにはその仕組みがある。

コマンドラインツールのdatagen_from_ddlではそこまで複雑な仕事をさせられないので、自分でスクリプトを書くといい。

dummy_into_mysql.pl
#!/usr/bin/env perl
use strict;
use warnings;
use utf8;
use autodie;
use Data::Dumper;
use Data::Generator::FromDDL;

open my $fh, '<', $ARGV[0] or die "Could not open ddl: $!";
my $ddl = '';
foreach my $line (<$fh>) {
    $ddl .= $line;
}
close $fh;

my $generator = Data::Generator::FromDDL->new(
    {   ddl    => $ddl,
        parser => 'mysql',
    }
);

my $num = {
    all    => 1000000,
    tables => {
        followings => 5000000,
        likes => 20000000,
    }
};
$generator->generate($num);

こんな感じに、$ARGV[0]でddlファイル(mysqldump --no-dataで作ったもの)を指定するようなスクリプトを書いて、

$ perl dummy_into_mysql.pl dump.sql | mysql -u katryo -p mydb 

とすると、followingsには5000000件、likesには20000000件、それ以外には1000000件のレコードが入る。