パーティショニングとは
パーティショニングとは、
パーティショニングを行うことで巨大なデータを複数に分割でき、
今回は、
パーティショニングの種類
パーティショニングには複数の種類があります。
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テーブルのデータと交換されていることが確認できました。
まとめ
今回はパーティショニングについて簡単に説明していきました。パーティショニングはデータの管理等には便利ですが、