LoginSignup
5
3

More than 5 years have passed since last update.

`MariaDB 10.2.13`によるパーティショニング(PARTITION BY)の動作検証

Last updated at Posted at 2018-04-19

MariaDB 10.2.13によるパーティショニング(PARTITION BY)の動作検証

環境

環境 概要
0 IPアドレス 192.168.33.50
1 Vagrant 2.0.3
2 CentOS 7(config.vm.box = "centos/7")
3 MariaDB 10.2.13
4 MariaDBのrootパスワード Password0419

事前準備

以下の記事を参考に、CentOS7の環境が構築済みの状態であること。
Vagrant2.0.3を使ったCentOS7.4の環境構築

やりたいこと

1つのDB内で、複数のユーザを管理するシステムは数多く存在すると思います。
やりたいこととして、他のユーザが登録したデータを相互に参照することはしないため、
他ユーザの登録件数に依存して検索速度が低下しないように、パーティショニングの機能を使って実現できるのか。ということを検証してみたいと思います。

環境準備

  • CentOS7にインストール済みのMariaDBをアンインストールする。
> yum -y remove mariadb-*
  • CentOS7用のMariaDB 10.2をyumでインストールするため、リポジトリを追加する。
> vim /etc/yum.repos.d/MariaDB.repo

[mariadb]
name = MariaDB
baseurl = http://yum.mariadb.org/10.2/centos7-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1
  • MariaDB 10.2をインストールする。
> yum -y install MariaDB-server MariaDB-client MariaDB-devel
  • インストールが正常に完了しているか確認するため、以下のコマンドを実行する。
> mysql --version

mysql  Ver 15.1 Distrib 10.2.13-MariaDB, for Linux (x86_64) using readline 5.1
  • MariaDBをインストールすると、設定ファイルは/etc/my.cnf.d/配下に配置される仕組みとなっているが、 実際にはほとんど設定ファイルが入っていない。 そのため、/usr/share/mysql/配下にあるサンプルのcnfファイルをコピーして流用する。
> ls -l /usr/share/mysql/my-*.cnf

-rw-r--r--. 1 root root  4920 Feb 12 16:58 /usr/share/mysql/my-huge.cnf
-rw-r--r--. 1 root root 20441 Feb 12 16:58 /usr/share/mysql/my-innodb-heavy-4G.cnf
-rw-r--r--. 1 root root  4907 Feb 12 16:58 /usr/share/mysql/my-large.cnf
-rw-r--r--. 1 root root  4920 Feb 12 16:58 /usr/share/mysql/my-medium.cnf
-rw-r--r--. 1 root root  2846 Feb 12 16:58 /usr/share/mysql/my-small.cnf

> cp -p /usr/share/mysql/my-medium.cnf /etc/my.cnf.d/server.cnf
  • server.cnfを修正して文字コードをutf8に指定し、データファイル格納先ディレクトリを指定する。
> vim /etc/my.cnf.d/server.cnf

[client]
#password       = your_password
port            = 3306
socket          = /var/lib/mysql/mysql.sock
default-character-set = utf8  ### 追加

# Here follows entries for some specific programs

# The MariaDB server
[mysqld]
port            = 3306
socket          = /var/lib/mysql/mysql.sock
skip-external-locking
key_buffer_size = 16M
max_allowed_packet = 1M
table_open_cache = 64
sort_buffer_size = 512K
net_buffer_length = 8K
read_buffer_size = 256K
read_rnd_buffer_size = 512K
myisam_sort_buffer_size = 8M
datadir=/var/lib/mysql          #### 追加
character-set-server = utf8     #### 追加
  • MariaDBのサービス自動起動を設定し、サービスを起動する。
> systemctl enable mariadb.service
> systemctl start mariadb.service
> systemctl status mariadb.service
  • 初期設定(rootのパスワードなどを設定)
> /usr/bin/mysql_secure_installation

Enter current password for root (enter for none):{何も入力せずEnter}
Set root password? [Y/n] Y
New password: Password0419
Re-enter new password: Password0419
Remove anonymous users?[Y/n] Y
Disallow root login remotely? [Y/n] Y    ← rootユーザのリモートログイン禁止
Remove test database and access to it? [Y/n] Y
Reload privilege tables now? [Y/n] Y    ← 権限テーブルの再読み込み
Thanks for using MariaDB!
  • DBを作成する。
> mysql -u root -p

MariaDB [(none)]> CREATE DATABASE sample DEFAULT CHARACTER SET utf8;
  • 新規ユーザーを追加し、全てのIPアドレスからアクセス可能にする。
MariaDB [(none)]> CREATE USER 'test'@'%' IDENTIFIED BY 'test';
MariaDB [(none)]> GRANT ALL ON *.* TO test;
  • 作成したユーザーでログインし、テーブルを作成する。
    MariaDB [(none)]> exit
    # mysql -u test -p
    MariaDB [(none)]> connect sample
    MariaDB [(none)]> create table users(user_id int auto_increment primary key, user_name text not null, create_dt date not null);
    MariaDB [sample]>
    create table emotion_dic(id int auto_increment primary key
     , user_id int not null
     , entry_word text not null
     , reading text not null
     , part text not null
     , emotion_real_number double(20,10) not null);
    MariaDB [sample]> insert into users(user_name, create_dt) values ('A', now());
    Query OK, 1 row affected, 1 warning (0.00 sec)

    MariaDB [sample]> insert into users(user_name, create_dt) values ('B', now());
    Query OK, 1 row affected, 1 warning (0.01 sec)

    MariaDB [sample]> insert into users(user_name, create_dt) values ('C', now());
    Query OK, 1 row affected, 1 warning (0.00 sec)

    MariaDB [sample]> insert into users(user_name, create_dt) values ('D', now());
    Query OK, 1 row affected, 1 warning (0.00 sec)
MariaDB [sample]> LOAD DATA LOCAL INFILE '/home/vagrant/emotion_dic_data.csv'
    -> INTO TABLE emotion_dic
    -> FIELDS
    ->     TERMINATED BY ','
    ->     OPTIONALLY ENCLOSED BY '"'
    ->     ESCAPED BY ''
    -> LINES
    ->     STARTING BY ''
    ->     TERMINATED BY '\r\n'
    -> (
    ->  user_id,
    ->  entry_word,
    ->  reading,
    ->  part,
    ->  emotion_real_number
    -> );
    Query OK, 668980 rows affected, 1 warning (3.22 sec)
    Records: 668980  Deleted: 0  Skipped: 0  Warnings: 1
  • ここまでの状態ではパーティショニングを実現していないため、1つのパーティションとなっている。
SELECT TABLE_SCHEMA,TABLE_NAME,PARTITION_NAME,PARTITION_ORDINAL_POSITION,TABLE_ROWS
 FROM INFORMATION_SCHEMA.PARTITIONS
 WHERE TABLE_NAME='emotion_dic';
+--------------+-------------+----------------+----------------------------+------------+
| TABLE_SCHEMA | TABLE_NAME  | PARTITION_NAME | PARTITION_ORDINAL_POSITION | TABLE_ROWS |
+--------------+-------------+----------------+----------------------------+------------+
| sample       | emotion_dic | NULL           |                       NULL |     667329 |
+--------------+-------------+----------------+----------------------------+------------+
1 row in set (0.03 sec)

パーティショニング前の負荷試験

上述している環境準備が完了した時点で、emotion_dicテーブルには66万件のデータが登録済みとなっている。
この状態のデータに対してMySQLが提供している負荷試験用のコマンド「mysqlslap」を利用して、
SELECTの負荷試験を行います。

ここでは、以下のSELECT文を1クライアントから1000回実行している。

SELECT * FROM emotion_dic WHERE user_id = 3 AND entry_word LIKE '%負%';
# mysqlslap --no-defaults --user=test --password=test --concurrency=1 --iterations=1000 --engine=innodb --create-schema=sample --no-drop --delimiter=";" --query="SELECT * FROM emotion_dic WHERE user_id = 3 AND entry_word LIKE '%負%';"
Benchmark
        Running for engine innodb
        Average number of seconds to run all queries: 0.325 seconds
        Minimum number of seconds to run all queries: 0.296 seconds
        Maximum number of seconds to run all queries: 0.548 seconds
        Number of clients running queries: 1
        Average number of queries per client: 1

パーティショニング後の負荷試験

まずはemotion_dicテーブルにパーティションの設定
と思ったら、パーティション設定するカラムはPKを含んでいないといけない。というようなことを言われる
※正確にはUNIQUE KEY制約のカラムを1つ以上指定する必要がある。
UNIQUE KEY (col1, col2)
UNIQUE KEY (col3)
の2つが指定されているテーブルが存在する場合は、
partition by list(col3)はOKだけど、
partition by list(col1)はNG。

mysql -u test -p
MariaDB [(none)]> connect sample
MariaDB [sample]> alter table emotion_dic partition by list(user_id) (
    ->     partition p_user1 values in (1),
    ->     partition p_user2 values in (2),
    ->     partition p_user3 values in (3),
    ->     partition p_user4 values in (4),
    ->     partition p_user5 values in (5),
    ->     partition p_user6 values in (6)
    -> );
ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function

仕方ないので、emotiono_dicのPKである「id」の列を削除してみる。

MariaDB [sample]> ALTER TABLE emotion_dic DROP COLUMN id;
Query OK, 668980 rows affected (1.80 sec)
Records: 668980  Duplicates: 0  Warnings: 0

もう一度パーティションの設定

MariaDB [sample]>
alter table emotion_dic partition by list(user_id) (
 partition p_user0 values in (0) engine = InnoDB,
 partition p_user1 values in (1) engine = InnoDB,
 partition p_user2 values in (2) engine = InnoDB,
 partition p_user3 values in (3) engine = InnoDB,
 partition p_user4 values in (4) engine = InnoDB,
 partition p_user5 values in (5) engine = InnoDB,
 partition p_user6 values in (6) engine = InnoDB,
 partition p_user7 values in (7) engine = InnoDB
);
Query OK, 668980 rows affected (1.75 sec)
Records: 668980  Duplicates: 0  Warnings: 0

パーティション設定が完了しているか確認する。

MariaDB [sample]>
SELECT
TABLE_SCHEMA,TABLE_NAME,PARTITION_NAME,PARTITION_ORDINAL_POSITION,TABLE_ROWS
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME='emotion_dic';
+--------------+-------------+----------------+----------------------------+------------+
| TABLE_SCHEMA | TABLE_NAME  | PARTITION_NAME | PARTITION_ORDINAL_POSITION | TABLE_ROWS |
+--------------+-------------+----------------+----------------------------+------------+
| sample       | emotion_dic | p_user0        |                          1 |          0 |
| sample       | emotion_dic | p_user1        |                          2 |       4734 |
| sample       | emotion_dic | p_user2        |                          3 |     109840 |
| sample       | emotion_dic | p_user3        |                          4 |     110187 |
| sample       | emotion_dic | p_user4        |                          5 |     110830 |
| sample       | emotion_dic | p_user5        |                          6 |     109890 |
| sample       | emotion_dic | p_user6        |                          7 |      58739 |
| sample       | emotion_dic | p_user7        |                          8 |      58828 |
+--------------+-------------+----------------+----------------------------+------------+
8 rows in set (0.00 sec)

性能評価

# mysqlslap --no-defaults --user=test --password=test --concurrency=1 --iterations=1000 --engine=innodb --create-schema=sample --no-drop --delimiter=";" --query="SELECT * FROM emotion_dic WHERE user_id = 3 AND entry_word LIKE '%負%';"
Benchmark
        Running for engine innodb
        Average number of seconds to run all queries: 0.068 seconds
        Minimum number of seconds to run all queries: 0.063 seconds
        Maximum number of seconds to run all queries: 0.229 seconds
        Number of clients running queries: 1
        Average number of queries per client: 1

パーティショニングの設定に応じた負荷試験 結果まとめ

以下の条件で行った負荷試験の結果をまとめて記載する。

負荷試験の条件

クライアント数(concurrency) 繰り返し数(iterations)
1 1 1000
2 10 100
3 100 10

1の実行結果

    -- パーティショニング前
    Benchmark
            Running for engine innodb
            Average number of seconds to run all queries: 0.397 seconds
            Minimum number of seconds to run all queries: 0.305 seconds
            Maximum number of seconds to run all queries: 0.708 seconds
            Number of clients running queries: 1
            Average number of queries per client: 1

    -- パーティショニング後
    Benchmark
        Running for engine innodb
        Average number of seconds to run all queries: 0.063 seconds
        Minimum number of seconds to run all queries: 0.059 seconds
        Maximum number of seconds to run all queries: 0.126 seconds
        Number of clients running queries: 1
        Average number of queries per client: 1

2の実行結果

    -- パーティショニング前
    Benchmark
        Running for engine innodb
        Average number of seconds to run all queries: 3.309 seconds
        Minimum number of seconds to run all queries: 3.095 seconds
        Maximum number of seconds to run all queries: 4.576 seconds
        Number of clients running queries: 10
        Average number of queries per client: 1

    -- パーティショニング後
    Benchmark
        Running for engine innodb
        Average number of seconds to run all queries: 0.682 seconds
        Minimum number of seconds to run all queries: 0.613 seconds
        Maximum number of seconds to run all queries: 1.050 seconds
        Number of clients running queries: 10
        Average number of queries per client: 1

3の実行結果

    -- パーティショニング前
    Benchmark
        Running for engine innodb
        Average number of seconds to run all queries: 33.190 seconds
        Minimum number of seconds to run all queries: 31.768 seconds
        Maximum number of seconds to run all queries: 35.018 seconds
        Number of clients running queries: 100
        Average number of queries per client: 1

    -- パーティショニング後
    Benchmark
        Running for engine innodb
        Average number of seconds to run all queries: 6.686 seconds
        Minimum number of seconds to run all queries: 6.257 seconds
        Maximum number of seconds to run all queries: 7.533 seconds
        Number of clients running queries: 100
        Average number of queries per client: 1

まとめ

他のユーザの件数増加に伴う検索性能の低下を抑えるため、
パーティショニングを使うことで解消することは可能だが、実際にはサロゲートキーのような
auto_incrementのid項目を設けたいケースも多く発生するため、UNIQUE KEY制約が含まれるテーブルをパーティショニングする場合、
そのキーをパーティショニングキーとして含めなければいけない制約は非常に苦しいところ。
条件によって使える。といった印象か。

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3