パーティショニングとは
パーティショニングとは、
パーティショニングを行うことで巨大なデータを複数に分割でき、
今回は、
パーティショニングの種類
パーティショニングには複数の種類があります。
RANGEパーティショニング
範囲で指定されるパーティショニング方法になります。数値型を用いて、
REATE TABLE t1 ( id int NOT NULL, days DATE NOT NULL ) PARTITION BY RANGE (id) ( PARTITION p0 VALUES LESS THAN (3), PARTITION p1 VALUES LESS THAN (5), PARTITION p2 VALUES LESS THAN (10), PARTITION p3 VALUES LESS THAN (15) );
LISTパーティショニング
事前に定義したデータのリストの情報をもとにパーティショニングする方法になります。パーティショニングを定義する際に、
CREATE TABLE t2 ( id int(2), days date ) ENGINE=InnoDB PARTITION BY LIST(id)( PARTITION p1 VALUES IN (1,2), PARTITION p2 VALUES IN (3,4,5), PARTITION p3 VALUES IN (6,7,8,9,10), PARTITION p4 VALUES IN (11,15) );
HASHパーティショニング
HASHパーティショニングは整数型のカラムをもとにHASH値を定め、
CREATE TABLE t3 ( id int(2), days date ) ENGINE=InnoDB PARTITION BY HASH(id) PARTITIONS 10; ;
HASH値の計算式は以下の通りです。
N = MOD(<整数型のカラム>, <分割数>)
KEYパーティショニング
KEYパーティショニングは主キーまたはユニークキーを内部でハッシュ化してパーティショニングします。
CREATE TABLE t4 ( id int(2) PRIMARY KEY, days date ) ENGINE=InnoDB PARTITION BY KEY() PARTITIONS 10; ;
パーティションテーブルの操作方法
では実際にパーティショニングされたテーブルを作成、
パーティショニングされたテーブルを定義する場合、
CREATE TABLE `t1` ( `id` int(11), `days` date ) ENGINE=InnoDB PARTITION BY RANGE (year(days)) PARTITION p0 VALUES LESS THAN (1900) ENGINE = InnoDB, PARTITION p1 VALUES LESS THAN (1950) ENGINE = InnoDB, PARTITION p2 VALUES LESS THAN (2000) ENGINE = InnoDB, PARTITION p3 VALUES LESS THAN (2050) ENGINE = InnoDB) ;
生成されたテーブルを確認してみます。
show create table t1\G *************************** 1. row *************************** Table: t1 Create Table: CREATE TABLE `t1` ( `id` int(11) DEFAULT NULL, `days` date DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin /*!50100 PARTITION BY RANGE (year(days)) (PARTITION p0 VALUES LESS THAN (1900) ENGINE = InnoDB, PARTITION p1 VALUES LESS THAN (1950) ENGINE = InnoDB, PARTITION p2 VALUES LESS THAN (2000) ENGINE = InnoDB, PARTITION p3 VALUES LESS THAN (2050) ENGINE = InnoDB) */ 1 row in set (0.00 sec)
さらに、
mysql > BEGIN; Query OK, 0 rows affected (0.00 sec) mysql > INSERT INTO t1(id, days) VALUES (1,'1969-12-13'),(2,'1973-5-5'),(3,'1834-4-18'),(4,'2000-1-1'),(5,'1923-6-8'),(6,'2012-7-19'),(7,'1917-2-1'),(8,'1999-12-31'),(9,'2017-8-15'),(10,'2005-8-10'); Query OK, 10 rows affected (0.00 sec) Records: 10 Duplicates: 0 Warnings: 0 mysql > COMMIT; Query OK, 0 rows affected (0.01 sec)
mysql > SELECT COUNT(*) FROM t1; +----------+ | count(1) | +----------+ | 10 | +----------+ 1 row in set (0.00 sec)
データを挿入することができました。
これらのデータは、
mysql >SELECT TABLE_NAME, PARTITION_NAME, TABLE_ROWS, AVG_ROW_LENGTH, DATA_LENGTH FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 't1' ;+------------+----------------+------------+----------------+-------------+ | TABLE_NAME | PARTITION_NAME | TABLE_ROWS | AVG_ROW_LENGTH | DATA_LENGTH | +------------+----------------+------------+----------------+-------------+ | t1 | p0 | 1 | 16384 | 16384 | | t1 | p1 | 2 | 8192 | 16384 | | t1 | p2 | 3 | 5461 | 16384 | | t1 | p3 | 4 | 4096 | 16384 | +------------+----------------+------------+----------------+-------------+ 4 rows in set (0.00 sec)
上記のようにPARTITION_
ここで対象のdatadirの対象のdatabaseからファイルを確認してみます。
$ ls -l t1#P#*.ibd -rw-r----- 1 mysql mysql 98304 8月 15 12:52 2017 t1#P#p0.ibd -rw-r----- 1 mysql mysql 98304 8月 15 12:52 2017 t1#P#p1.ibd -rw-r----- 1 mysql mysql 98304 8月 15 12:53 2017 t1#P#p2.ibd -rw-r----- 1 mysql mysql 98304 8月 15 12:52 2017 t1#P#p3.ibd
idbファイルが4つ生成されています。パーティショニングを用いるとデータは各ファイルに格納されていますが、
NULL値やパーティションの条件にそぐわない値をどう扱うのか
パーティショニングのKEYとして、
CREATE TABLE `t2` ( `id` int(11), `days` date ) ENGINE=InnoDB PARTITION BY RANGE (id) (PARTITION p0 VALUES LESS THAN (3) ENGINE = InnoDB, PARTITION p1 VALUES LESS THAN (5) ENGINE = InnoDB, PARTITION p2 VALUES LESS THAN (10) ENGINE = InnoDB, PARTITION p3 VALUES LESS THAN (15) ENGINE = InnoDB) ;
mysql > INSERT INTO t2(id, days) VALUES(null,'2017-08-13'); Query OK, 1 row affected (0.01 sec) mysql > INSERT INTO t2(id, days) VALUES(16,'2017-08-13'); ERROR 1526 (HY000): Table has no partition for value 16
上記のようにNULL値を挿入することはできましたが、
MySQLのパーティショニングは、
パーティションの選択について
パーティションを選択してSQLを実行
パーティショニングされたテーブルに対して特定のパーティションのみにSQLを実行する場合は、
mysql > SELECT * FROM t1 PARTITION (p1); +----+------------+ | id | days | +----+------------+ | 5 | 1923-06-08 | | 7 | 1917-02-01 | +----+------------+ 2 rows in set (0.00 sec)
p1のパーティションに入っているデータのみを取得することができました。これは、SELECT * FROM t1 WHERE between days '1900-01-01' and '1949-12-31'
と同じ意味になります。
実際に実行計画をとってみると、
mysql > EXPLAIN SELECT * FROM t1 PARTITION (p1); +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+ | 1 | SIMPLE | t1 | p1 | ALL | NULL | NULL | NULL | NULL | 2 | 100.00 | NULL | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+ 1 row in set, 1 warning (0.00 sec)
mysql > EXPLAIN SELECT * FROM t1; +----+-------------+-------+-------------+------+---------------+------+---------+------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+-------------+------+---------------+------+---------+------+------+----------+-------+ | 1 | SIMPLE | t1 | p0,p1,p2,p3 | ALL | NULL | NULL | NULL | NULL | 6 | 100.00 | NULL | +----+-------------+-------+-------------+------+---------------+------+---------+------+------+----------+-------+ 1 row in set, 1 warning (0.00 sec)
パーティションプルーニング
パーティションプルーニングとは、
パーティションプルーニングはWHERE句の条件が下記の条件のとき実行されます。
- パーティションのKEYとなるカラム = (または<、
>、 <=、 >=,<>) 値 - パーティションのKEYとなるカラム in (値1,値2, ...)
先ほど作成したテーブルt1に対して、
実際に実行計画を取ってみます。
mysql > EXPLAIN SELECT * FROM t1 WHERE days < '1930-01-01'; +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ | 1 | SIMPLE | t1 | p0,p1 | ALL | NULL | NULL | NULL | NULL | 2 | 50.00 | Using where | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ 1 row in set, 1 warning (0.00 sec)
partitionsがp0、
EXCHANGE PARTITIONについて
EXCHANGE PARTITIONは5.
mysql > CREATE TABLE t3 ( -> id int(11), -> days date -> ) ENGINE=InnoDB -> ; Query OK, 0 rows affected (0.03 sec)
t1テーブルのp2パーティションを単独のテーブルとしてt3にコピーします。
EXCHANGE PARTITIONを実行する時は、ALTER TABLEにEXCHANGE PARTITION <パーティション名> WITH TABLE <交換するテーブル名>
を用います。
mysql > SELECT COUNT(1) FROM t1; +----------+ | COUNT(1) | +----------+ | 10 | +----------+ 1 row in set (0.00 sec) mysql > SELECT COUNT(*) FROM t1; +----------+ | COUNT(1) | +----------+ | 10 | +----------+ 1 row in set (0.00 sec) mysql > SELECT COUNT(1) FROM t3; +----------+ | COUNT(1) | +----------+ | 0 | +----------+ 1 row in set (0.00 sec)
mysql > SELECT -> TABLE_NAME, -> PARTITION_NAME, -> TABLE_ROWS, -> AVG_ROW_LENGTH, -> DATA_LENGTH -> FROM -> INFORMATION_SCHEMA.PARTITIONS -> WHERE -> TABLE_NAME = 't1' -> ; +------------+----------------+------------+----------------+-------------+ | TABLE_NAME | PARTITION_NAME | TABLE_ROWS | AVG_ROW_LENGTH | DATA_LENGTH | +------------+----------------+------------+----------------+-------------+ | t1 | p0 | 1 | 16384 | 16384 | | t1 | p1 | 2 | 8192 | 16384 | | t1 | p2 | 3 | 5461 | 16384 | | t1 | p3 | 4 | 4096 | 16384 | +------------+----------------+------------+----------------+-------------+ 4 rows in set (0.00 sec)
mysql > ALTER TABLE t1 EXCHANGE PARTITION p2 WITH TABLE t3; Query OK, 0 rows affected (0.05 sec) mysql > SELECT COUNT(*) FROM t1; +----------+ | COUNT(1) | +----------+ | 7 | +----------+ 1 row in set (0.00 sec) mysql > SELECT COUNT(*) FROM t3; +----------+ | COUNT(1) | +----------+ | 3 | +----------+ 1 row in set (0.00 sec) mysql > SELECT * FROM t3; +------+------------+ | id | days | +------+------------+ | 1 | 1969-12-13 | | 2 | 1973-05-05 | | 8 | 1999-12-31 | +------+------------+ 3 rows in set (0.00 sec)
t1テーブルのp3パーティションに入っているデータがt3テーブルのデータと交換されていることが確認できました。
まとめ
今回はパーティショニングについて簡単に説明していきました。パーティショニングはデータの管理等には便利ですが、