昨年からMySQLチームがオフィシャルレポジトリーをDockerに公開し、
最近少しずつ利用している方も増えてきて、
開発環境などでは簡単にDBが準備出来て工数削減も出来、
大活躍出来る仕組みなので簡単にレビューしておきます。

[Dockerレポジトリ]
https://hub.docker.com/_/mysql/ (Docker Team)
https://hub.docker.com/r/mysql/mysql-server/ (MySQL team at Oracle)

Tagに関しては、此方を確認下さい。(指定しない場合は、最新のイメージがダウンロードされます)
https://hub.docker.com/r/mysql/mysql-server/tags/

レポジトリーにはDockerのオフィシャルレポジトリーとMySQLチームが公開しているオフィシャルレポジトリーがあります。
イメージをPULLすると以下のような感じになります。

既に、docker pull mysql:5.7.10コマンドでDockerオフィシャルレポジトリからイメージをダウンロード済みの状態です。
追加で、MySQL@OracleのオフィシャルレポジトリーからDockerのイメージをダウンロードしてみます。
サイズだけ見ると、MySQL@Oracleのオフィシャルレポジトリーからダウンロードしたイメージの方がサイズは小さいです。


[root@DockerHost docker]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
mysql               5.7.10              ea0aca21950d        3 weeks ago         360.3 MB
[root@DockerHost docker]# docker pull mysql/mysql-server:5.7.10
5.7.10: Pulling from mysql/mysql-server
f359075ce4d8: Pull complete 
df9c05f5df07: Pull complete 
bea04efc3319: Pull complete 
14204cc431b4: Pull complete 
249d5b7b31c1: Pull complete 
70a368114c59: Pull complete 
c5b90de0636a: Pull complete 
59e355dc43f6: Pull complete 
f03e996fb5a3: Pull complete 
69497ffa3023: Pull complete 
e472f1765697: Pull complete 
Digest: sha256:c9266386460cfb302d21615bbe8f6a16166b2376eb371095df7cc9a1c9cf6da1
Status: Downloaded newer image for mysql/mysql-server:5.7.10
[root@DockerHost docker]# docker images
REPOSITORY           TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
mysql                5.7.10              ea0aca21950d        3 weeks ago         360.3 MB
mysql/mysql-server   5.7.10              e472f1765697        4 weeks ago         294.6 MB
[root@DockerHost docker]# 

Dockerオフィシャルイメージを利用してMySQLを構築してみます。
インスタンス作成時に、データディレクトリーを指定、オプションファイルを指定、インスタンス作成と同時に
データベース作成する為に以下のスクリプトを配置してあります。ソースを確認すると*.sqlか*.shを配置しておくと、
DB作成時に読み込んでSQL文を実行してくれます。(初期共通アカウントやDB作成に使えます)

run


[root@DockerHost docker]# ls -l /docker/init_script/sakila-db/init-docker-sakila.sql 
-rw-r--r-- 1 root root 3421501 Jan  8 01:01 /docker/init_script/sakila-db/init-docker-sakila.sql
[root@DockerHost docker]# 


[root@DockerHost docker]# docker ps -a 
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
[root@DockerHost docker]# docker run --name my_docker01 -v /docker/docker01:/var/lib/mysql -v /docker/option1:/etc/mysql/conf.d -v /docker/init_script/sakila-db:/docker-entrypoint-initdb.d -e MYSQL_ROOT_PASSWORD=mysql -d mysql:5.7.10
5152a22b2aa0c724bd260552205ebf566a21b9d854a54921f02a96e40817a930
[root@DockerHost docker]# docker ps -a 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
5152a22b2aa0        mysql:5.7.10        "/entrypoint.sh mysql"   11 seconds ago      Up 9 seconds        3306/tcp            my_docker01
[root@DockerHost docker]# 

Docker Inspectコマンドでパスのマッピングを確認


[root@DockerHost docker]# docker inspect my_docker01 | egrep 'Source|Destination'
            "Source": "/docker/docker01",
            "Destination": "/var/lib/mysql",
            "Source": "/docker/option1",
            "Destination": "/etc/mysql/conf.d",
            "Source": "/docker/init_script/sakila-db",
            "Destination": "/docker-entrypoint-initdb.d",
[root@DockerHost docker]# 

作成したインスタンスに接続して、初期設定状態を確認してみます。
確認: インスタンス接続、オプションファイルの読み込み、初期DBの作成状態。

[root@DockerHost docker]# docker exec -it my_docker01 mysql -uroot -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.10-log MySQL Community Server (GPL)

Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

root@localhost [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sakila             |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

root@localhost [(none)]> show tables from sakila;
+----------------------------+
| Tables_in_sakila           |
+----------------------------+
| actor                      |
| actor_info                 |
| address                    |
| category                   |
| city                       |
| country                    |
| customer                   |
| customer_list              |
| film                       |
| film_actor                 |
| film_category              |
| film_list                  |
| film_text                  |
| inventory                  |
| language                   |
| nicer_but_slower_film_list |
| payment                    |
| rental                     |
| sales_by_film_category     |
| sales_by_store             |
| staff                      |
| staff_list                 |
| store                      |
+----------------------------+
23 rows in set (0.07 sec)

root@localhost [(none)]> show variables like 'char%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | utf8                       |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.04 sec)

root@localhost [(none)]> 

次に、MySQL@Oracleチームがオフィシャルに提供しているオフィシャルイメージを利用してインスタンスを作成してみます。
※こちらのイメージを利用する場合は、オプションファイルの指定方法が少し異なります。(/etc/my.cnf)


[root@DockerHost docker]# docker ps -a 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
5152a22b2aa0        mysql:5.7.10        "/entrypoint.sh mysql"   53 minutes ago      Up 53 minutes       3306/tcp            my_docker01
[root@DockerHost docker]# docker run --name my_docker02 -v /docker/docker02:/var/lib/mysql -v /docker/init_script/sakila-db:/docker-entrypoint-initdb.d -e MYSQL_ROOT_PASSWORD=mysql -d mysql/mysql-server:5.7.10
f59d1fd222d7b15ff0f0dfa3879254730734e17451fde56aeb402279f355941e
[root@DockerHost docker]# docker ps -a 
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS              PORTS               NAMES
f59d1fd222d7        mysql/mysql-server:5.7.10   "/entrypoint.sh mysql"   2 seconds ago       Up 1 seconds        3306/tcp            my_docker02
5152a22b2aa0        mysql:5.7.10                "/entrypoint.sh mysql"   53 minutes ago      Up 53 minutes       3306/tcp            my_docker01
[root@DockerHost docker]# 

作成したインスタンスとDBの確認。(こちらは、OptionファイルはしていないのでDefaultです)


[root@DockerHost docker]# docker exec -it my_docker02 mysql -uroot -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.10 MySQL Community Server (GPL)

Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sakila             |
| sys                |
+--------------------+
5 rows in set (0.02 sec)

mysql> show tables from sakila;
+----------------------------+
| Tables_in_sakila           |
+----------------------------+
| actor                      |
| actor_info                 |
| address                    |
| category                   |
| city                       |
| country                    |
| customer                   |
| customer_list              |
| film                       |
| film_actor                 |
| film_category              |
| film_list                  |
| film_text                  |
| inventory                  |
| language                   |
| nicer_but_slower_film_list |
| payment                    |
| rental                     |
| sales_by_film_category     |
| sales_by_store             |
| staff                      |
| staff_list                 |
| store                      |
+----------------------------+
23 rows in set (0.00 sec)

mysql> show variables like 'char%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | latin1                     |
| character_set_connection | latin1                     |
| character_set_database   | latin1                     |
| character_set_filesystem | binary                     |
| character_set_results    | latin1                     |
| character_set_server     | latin1                     |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.02 sec)

mysql> 

イメージは停止しても、削除(rm)しなければ継続利用出来るので以下のようにサービスを停止して再開しても、
作成したデータなどは無くならず利用する事が可能です。


[root@DockerHost docker]# docker ps -a 
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS              PORTS               NAMES
f59d1fd222d7        mysql/mysql-server:5.7.10   "/entrypoint.sh mysql"   10 minutes ago      Up 10 minutes       3306/tcp            my_docker02
5152a22b2aa0        mysql:5.7.10                "/entrypoint.sh mysql"   About an hour ago   Up About an hour    3306/tcp            my_docker01
[root@DockerHost docker]# docker stop f59d1fd222d7
f59d1fd222d7
[root@DockerHost docker]# docker stop 5152a22b2aa0
5152a22b2aa0
[root@DockerHost docker]# docker ps -a 
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS                      PORTS               NAMES
f59d1fd222d7        mysql/mysql-server:5.7.10   "/entrypoint.sh mysql"   11 minutes ago      Exited (0) 13 seconds ago                       my_docker02
5152a22b2aa0        mysql:5.7.10                "/entrypoint.sh mysql"   About an hour ago   Exited (0) 3 seconds ago                        my_docker01
[root@DockerHost docker]# docker start f59d1fd222d7
f59d1fd222d7
[root@DockerHost docker]# docker ps -a 
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS                      PORTS               NAMES
f59d1fd222d7        mysql/mysql-server:5.7.10   "/entrypoint.sh mysql"   11 minutes ago      Up 2 seconds                3306/tcp            my_docker02
5152a22b2aa0        mysql:5.7.10                "/entrypoint.sh mysql"   About an hour ago   Exited (0) 20 seconds ago                       my_docker01
[root@DockerHost docker]# docker exec -it my_docker02 mysql -uroot -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.10 MySQL Community Server (GPL)

Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sakila             |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

mysql> 

補足: MySql@oracleチームのオフィシャルイメージの場合にオプションファイルを指定する場合は、以下のように実行します。


[root@DockerHost docker]# docker run --name my_docker02 -v /docker/docker02:/var/lib/mysql -v /docker/option2/my.cnf:/etc/my.cnf -v /docker/init_script/sakila-db:/docker-entrypoint-initdb.d -e MYSQL_ROOT_PASSWORD=mysql -d mysql/mysql-server:5.7.10
4fde03dc4cb5966bbfee79de92c2351f2b04812df77bf763b0e14755c3d51261
[root@DockerHost docker]# docker ps -a 
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS                      PORTS               NAMES
4fde03dc4cb5        mysql/mysql-server:5.7.10   "/entrypoint.sh mysql"   22 seconds ago      Up 21 seconds               3306/tcp            my_docker02
5152a22b2aa0        mysql:5.7.10                "/entrypoint.sh mysql"   About an hour ago   Exited (0) 24 minutes ago                       my_docker01
[root@DockerHost docker]# 

[root@DockerHost docker]# docker inspect my_docker02 | egrep 'Source|Destination'
            "Source": "/docker/docker02",
            "Destination": "/var/lib/mysql",
            "Source": "/docker/option2/my.cnf",
            "Destination": "/etc/my.cnf",
            "Source": "/docker/init_script/sakila-db",
            "Destination": "/docker-entrypoint-initdb.d",
[root@DockerHost docker]# 

参考:
https://hub.docker.com/r/mysql/mysql-server/
http://datacharmer.blogspot.jp/2015/10/mysql-docker-operations-part-1-getting.html


Generated_Column(生成列)とJSONデータを扱う場合に考慮しておく事
MySQL5.7.9とMySQL5.7.10以降で挙動が異なる為、念の為こちらにメモしておきます。
基本的には、MySQL5.7.10で改善されたという事になります。

http://bugs.mysql.com/bug.php?id=79552
>I think the behaviour you observed in 5.7.9 was actually a bug.
>The bug was fixed in 5.7.10, which is why you see different results now. There is some discussion about this in bug#78464 and bug#76834.

関連要望チケット from Morganさん
https://bugs.mysql.com/bug.php?id=78736

root@localhost [NEW57]> select @@version;
+-------------------------------------------+
| @@version                                 |
+-------------------------------------------+
| 5.7.10-enterprise-commercial-advanced-log |
+-------------------------------------------+
1 row in set (0.00 sec)

確認に利用したテーブル定義

root@localhost [NEW57]> show create table features\G
*************************** 1. row ***************************
       Table: features
Create Table: CREATE TABLE `features` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `feature` json NOT NULL,
  `feature_type` varchar(30) GENERATED ALWAYS AS (json_extract(`feature`,'$.type')) VIRTUAL,
  `feature_street` varchar(30) GENERATED ALWAYS AS (json_extract(`feature`,'$.properties.STREET')) VIRTUAL,
  PRIMARY KEY (`id`),
  KEY `idx_feature_type` (`feature_type`),
  KEY `idx_feature_street` (`feature_street`)
) ENGINE=InnoDB AUTO_INCREMENT=206561 DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

上記で定義された生成列からJSONデータをSELECTする場合
生成列のデータは””を含む為、SELECTした場合には””を付けなければいけない。

root@localhost [NEW57]> select id,feature_street from NEW57.features where feature_street = 'MARKET' limit 1;
Empty set (0.00 sec)

root@localhost [NEW57]> select id,feature_street from NEW57.features where feature_street = '"MARKET"' limit 1;
+-------+----------------+
| id    | feature_street |
+-------+----------------+
| 12250 | "MARKET"       |
+-------+----------------+
1 row in set (0.00 sec)

上記の挙動としては、CASTした時に”(ダブルクオート)をそのまま付けるからという事のようです。
CASTしないでそのままjson_extract関数でSELECTした場合は”(ダブルクオート)は不要です。詳細は以下の例を参照下さい。

root@localhost [NEW57]> select * from NEW57.features where cast(json_extract(feature,'$.properties.STREET') as char) = 'MARKET' limit 1;
Empty set (1.03 sec)

root@localhost [NEW57]> select * from NEW57.features where cast(json_extract(feature,'$.properties.STREET') as char) = '"MARKET"' limit 1;
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------+----------------+
| id    | feature                                                                                                                                                                                                                                                                                                                                                                                                                                                | feature_type | feature_street |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------+----------------+
| 12250 | {"type": "Feature", "geometry": {"type": "Polygon", "coordinates": [[[-122.39836263491878, 37.79189388899312, 0], [-122.39845248797837, 37.79233030084018, 0], [-122.39768507706792, 37.7924280850133, 0], [-122.39836263491878, 37.79189388899312, 0]]]}, "properties": {"TO_ST": "388", "BLKLOT": "0265003", "STREET": "MARKET", "FROM_ST": "388", "LOT_NUM": "003", "ST_TYPE": "ST", "ODD_EVEN": "E", "BLOCK_NUM": "0265", "MAPBLKLOT": "0265003"}} | "Feature"    | "MARKET"       |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------+----------------+
1 row in set (0.05 sec)


root@localhost [NEW57]> select * from NEW57.features where json_extract(feature,'$.properties.STREET') = '"MARKET"' limit 1;
Empty set (1.36 sec)

root@localhost [NEW57]> select * from NEW57.features where json_extract(feature,'$.properties.STREET') = 'MARKET' limit 1;
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------+----------------+
| id    | feature                                                                                                                                                                                                                                                                                                                                                                                                                                                | feature_type | feature_street |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------+----------------+
| 12250 | {"type": "Feature", "geometry": {"type": "Polygon", "coordinates": [[[-122.39836263491878, 37.79189388899312, 0], [-122.39845248797837, 37.79233030084018, 0], [-122.39768507706792, 37.7924280850133, 0], [-122.39836263491878, 37.79189388899312, 0]]]}, "properties": {"TO_ST": "388", "BLKLOT": "0265003", "STREET": "MARKET", "FROM_ST": "388", "LOT_NUM": "003", "ST_TYPE": "ST", "ODD_EVEN": "E", "BLOCK_NUM": "0265", "MAPBLKLOT": "0265003"}} | "Feature"    | "MARKET"       |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------+----------------+
1 row in set (0.08 sec)

JSON_EXTRACTと生成列を常に同じように”(ダブルクオート)を利用する事無く比較するには?
結論としては,CASTしてしまうと”(ダブルクオート)はついてしまうので、生成列を作る時に以下の例のように、
json_unquoteとjson_extractを同時に使う事で常に”(ダブルクオート)を利用する事無くJSONデータを参照する事が可能になります。

CREATE TABLE `features_with_unquote` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `feature` json NOT NULL,
  `feature_type` varchar(30) GENERATED ALWAYS AS (json_unquote(json_extract(`feature`,'$.type'))) VIRTUAL,
  `feature_street` varchar(30) GENERATED ALWAYS AS (json_unquote(json_extract(`feature`,'$.properties.STREET'))) VIRTUAL,
  PRIMARY KEY (`id`),
  KEY `idx_feature_type` (`feature_type`),
  KEY `idx_feature_street` (`feature_street`)
) ENGINE=InnoDB AUTO_INCREMENT=206561 DEFAULT CHARSET=utf8mb4;


root@localhost [NEW57]> insert into features_with_unquote(id,feature) select id,feature from features;
Query OK, 206560 rows affected (9.62 sec)
Records: 206560  Duplicates: 0  Warnings: 0

json_extractでJSONデータを参照

root@localhost [NEW57]> select * from NEW57.features_with_unquote where json_extract(feature,'$.properties.STREET') = 'MARKET' limit 1; 
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------+----------------+
| id    | feature                                                                                                                                                                                                                                                                                                                                                                                                                                                | feature_type | feature_street |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------+----------------+
| 12250 | {"type": "Feature", "geometry": {"type": "Polygon", "coordinates": [[[-122.39836263491878, 37.79189388899312, 0], [-122.39845248797837, 37.79233030084018, 0], [-122.39768507706792, 37.7924280850133, 0], [-122.39836263491878, 37.79189388899312, 0]]]}, "properties": {"TO_ST": "388", "BLKLOT": "0265003", "STREET": "MARKET", "FROM_ST": "388", "LOT_NUM": "003", "ST_TYPE": "ST", "ODD_EVEN": "E", "BLOCK_NUM": "0265", "MAPBLKLOT": "0265003"}} | Feature      | MARKET         |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------+----------------+
1 row in set (0.04 sec)

生成列の参照(json_unquoteとjson_extractで生成)

root@localhost [NEW57]> select * from NEW57.features_with_unquote where feature_street = 'MARKET' limit 1; 
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------+----------------+
| id    | feature                                                                                                                                                                                                                                                                                                                                                                                                                                                | feature_type | feature_street |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------+----------------+
| 12250 | {"type": "Feature", "geometry": {"type": "Polygon", "coordinates": [[[-122.39836263491878, 37.79189388899312, 0], [-122.39845248797837, 37.79233030084018, 0], [-122.39768507706792, 37.7924280850133, 0], [-122.39836263491878, 37.79189388899312, 0]]]}, "properties": {"TO_ST": "388", "BLKLOT": "0265003", "STREET": "MARKET", "FROM_ST": "388", "LOT_NUM": "003", "ST_TYPE": "ST", "ODD_EVEN": "E", "BLOCK_NUM": "0265", "MAPBLKLOT": "0265003"}} | Feature      | MARKET         |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------+----------------+
1 row in set (0.00 sec)

こちらの処理により常に、”(ダブルクオート)を付けずにデータが参照できるようになりました。

参照: 8.3.9 Optimizer Use of Generated Column Indexes


10月19日にMySQL5.7がGAになったので、新規追加されたJSONデータ型の確認を行いました。
JSONはXMLと同じように、スマートフォンアプリ用のAPIやB2BやB2C連携でJSON APIが多く使われているようです。

基本的な動作検証
1. 基本的な構文バリデーション機能
2. JSONデータ型とTEXT型のパフォーマンス差
3. JSONとGenerated Columnの連携によるインデックス利用とパフォーマンス
4. JSONドキュメントの部分アップデート

ちなみに、ザックリとGoogleで検索してみると以下のように多くのサイトがJSON用のAPIを提供していました。
Twitter
https://dev.twitter.com/rest/reference/get/statuses/user_timeline
原子力規制委員会
http://radioactivity.nsr.go.jp/data/ja/real/area_24000/2401_trend.json
Google API
https://storage.googleapis.com/maps-devrel/google.json
ぐるナビ
http://api.gnavi.co.jp/api/tools/?apitype=ver1_RestSearchAPI
シカゴ市
https://data.cityofchicago.org/resource/alternative-fuel-locations.json?$limit=100&$offset=50

1. 基本的な構文バリデーション機能

検証テーブル (TEXT型)

CREATE TABLE `employees_txt` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `data` text NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4

検証テーブル (JSON型)

CREATE TABLE `employees_json` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `data` json NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4

それぞれのテーブルに、構文ミスしたJSONデータを入れてみると以下のようになる。
JSONデータ型はINSERT時のバリデーションが正常に効いている。


root@localhost [NEW57]> INSERT INTO NEW57.employees_txt(data) VALUES ('{"id": 1, "name": "Jane"}');
Query OK, 1 row affected (0.00 sec)

root@localhost [NEW57]> INSERT INTO NEW57.employees_txt(data) VALUES ('{"id": 2, "name": "Joe"');
Query OK, 1 row affected (0.01 sec)

root@localhost [NEW57]> SELECT * FROM NEW57.employees_txt;
+----+---------------------------+
| id | data                      |
+----+---------------------------+
|  1 | {"id": 1, "name": "Jane"} |
|  2 | {"id": 2, "name": "Joe"   |
+----+---------------------------+
2 rows in set (0.00 sec)

root@localhost [NEW57]> INSERT INTO NEW57.employees_json(data) VALUES ('{"id": 1, "name": "Jane"}');
Query OK, 1 row affected (0.01 sec)

root@localhost [NEW57]> INSERT INTO NEW57.employees_json(data) VALUES ('{"id": 2, "name": "Joe"');
ERROR 3140 (22032): Invalid JSON text: "Missing a comma or '}' after an object member." at position 23 in value (or column) '{"id": 2, "name": "Joe"'.
root@localhost [NEW57]> SELECT * FROM NEW57.employees_json;
+----+---------------------------+
| id | data                      |
+----+---------------------------+
|  1 | {"id": 1, "name": "Jane"} |
+----+---------------------------+
1 row in set (0.00 sec)

root@localhost [NEW57]> 

2. JSONデータ型とTEXT型のパフォーマンス差
セミナーでも実施しましたが、以下のようなシンプルなテーブルに対して、
ダウンロードしてきた、20万6千件のJSONデータをインサートして参照レスポンス比較。

それぞれの参照クエリにて同じコマンドと同じデータでレスポンス比較
SELECT distinct json_extract(feature,’$.type’) as feature FROM NEW57.features_txt;
SELECT distinct json_extract(feature,’$.type’) as feature FROM NEW57.features_json;

結果としては、JSON型の方がTEXT型に比べて圧倒的に早い事が確認出来る。

[root@misc01 SOD2015]# ./json_and_text_without_index.sh 
INDEXの無いテーブルに対するSELECTを、TEXT型とJSONデータ型で比較します。
SELECT distinct json_extract(feature,'$.type') as feature FROM 各テーブル

【TEXT型】
mysql: [Warning] Using a password on the command line interface can be insecure.
+-----------+
| feature   |
+-----------+
| "Feature" |
+-----------+

real    0m9.724s
user    0m0.005s
sys     0m0.002s

【JSON型】
mysql: [Warning] Using a password on the command line interface can be insecure.
+-----------+
| feature   |
+-----------+
| "Feature" |
+-----------+

real    0m1.506s
user    0m0.004s
sys     0m0.004s
[root@misc01 SOD2015]# 

3. JSONとGenerated Columnの連携によるインデックス利用とパフォーマンス
JSONドキュメントのオブジェクトの中からSTREET名の部分からデータを抽出して列を作成しIndexを付与。

列:      json_extract(feature,’$.properties.STREET’))
インデックス: KEY `feature_street` (`feature_street`)

 

JSONデータ型のサンプルを入れたテーブル
mysql: [Warning] Using a password on the command line interface can be insecure.
*************************** 1. row ***************************
            id: 12250
       feature: {"type": "Feature", "geometry": {"type": "Polygon", "coordinates": [[[-122.39836263491878, 37.79189388899312, 0], [-122.39845248797837, 37.79233030084018, 0], [-122.39768507706792, 37.7924280850133, 0], [-122.39836263491878, 37.79189388899312, 0]]]}, "properties": {"TO_ST": "388", "BLKLOT": "0265003", "STREET": "MARKET", "FROM_ST": "388", "LOT_NUM": "003", "ST_TYPE": "ST", "ODD_EVEN": "E", "BLOCK_NUM": "0265", "MAPBLKLOT": "0265003"}}
  feature_type: "Feature"
feature_street: "MARKET"
Press [Enter] key to resume.

JSONデータ型とGenerated Columnを利用したテーブル
mysql: [Warning] Using a password on the command line interface can be insecure.
*************************** 1. row ***************************
       Table: features
Create Table: CREATE TABLE `features` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `feature` json NOT NULL,
  `feature_type` varchar(30) GENERATED ALWAYS AS (json_extract(feature,'$.type')) VIRTUAL,
  `feature_street` varchar(30) GENERATED ALWAYS AS (json_extract(feature,'$.properties.STREET')) VIRTUAL,
  PRIMARY KEY (`id`),
  KEY `feature_type` (`feature_type`),
  KEY `feature_street` (`feature_street`)
) ENGINE=InnoDB AUTO_INCREMENT=206561 DEFAULT CHARSET=utf8mb4
Press [Enter] key to resume.

JSONドキュメントに対して、INDEX検索が利用出来るか確認 -> where json_extract(feature,'$.properties.STREET') = '"MARKET"'
mysql: [Warning] Using a password on the command line interface can be insecure.
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: features
   partitions: NULL
         type: ref
possible_keys: feature_street
          key: feature_street
      key_len: 123
          ref: const
         rows: 808
     filtered: 100.00
        Extra: NULL
[root@misc01 SOD2015]# 

4. JSONドキュメントの部分アップデート
JSONドキュメントの一部をUPDATEする場合の処理方法確認。
TEXT型だと、全ての列データを入れ替える必要がありますが、JSONだと一部のみ変更可能です。

select id,body,json_extract(body,"$.price") as extract from T_JSON_DOC where id = 3;
+----+------------------------------------------------------------------------+---------+
| id | body                                                                   | extract |
+----+------------------------------------------------------------------------+---------+
|  3 | {"id": 3, "name": "冷蔵庫", "price": 50000, "Conditions": ["NEW", 2015]}| 50000   |
+----+------------------------------------------------------------------------+---------+

update T_JSON_DOC set T_JSON_DOC.body = JSON_REPLACE(body,"$.price",15000) 
where id = 3;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

select id,body,json_extract(body,"$.price") as extract from T_JSON_DOC where id = 3;
+----+----------------------------------------------------------------------- +---------+
| id | body                                                                   | extract |
+----+------------------------------------------------------------------------+---------+
|  3 | {"id": 3, "name": "冷蔵庫", "price": 15000, "Conditions": ["NEW", 2015]}| 15000   |
+----+------------------------------------------------------------------------+---------+

文字入れ替えに便利なJSONファンクション(例)
JSON_SET() 既存の値を置き換え、存在しない値を追加
JSON_INSERT() 既存の値を置き換えずに値を挿入
JSON_REPLACE() 既存の値のみを置き換えます

参照:
11.6 The JSON Data Type
https://dev.mysql.com/doc/refman/5.7/en/json.html

MySQL5.7セミナー資料
https://www-jp.mysql.com/news-and-events/seminar/downloads.html


MySQL5.7(5.7.9) Major Versionがリリースされました。
全文検索、JSONデータ型、Generalテーブルスペース, GIS,SQL Rewrite機能等、
色々と拡張されているのと同時にPrimary Keyベースの参照がMySQL5.6の2倍程度3倍程度、
パフォーマンスが良くなっているので、是非利用してみて頂ければと思います。

MySQL Community版ダウンロード
http://dev.mysql.com/downloads/

MySQL 商用版トライアル
http://edelivery.oracle.com/

昨晩からダウンロード出来るようになっていたので、
ダウンロードしてインストールしてみました。
既に、MySQL5.7.8RCがインストール済みだったので、アップグレードは5分程度で終わりました。
但し、5.7は初期設定の段階でテーブルスペースやPageサイズ等色々と設定可能ですので、
もしインストールして継続的に使う場合は最初に設計しても良いかもしれません。

[root@misc02 bin]# ./mysql_upgrade -u root -p
Enter password: 
Checking if update is needed.
Checking server version.
Running queries to upgrade MySQL server.
Checking system database.
mysql.columns_priv                                 OK
mysql.db                                           OK
mysql.engine_cost                                  OK
mysql.event                                        OK
mysql.func                                         OK
mysql.general_log                                  OK
mysql.gtid_executed                                OK
mysql.help_category                                OK
mysql.help_keyword                                 OK
mysql.help_relation                                OK
mysql.help_topic                                   OK
mysql.innodb_index_stats                           OK
mysql.innodb_table_stats                           OK
mysql.ndb_binlog_index                             OK
mysql.plugin                                       OK
mysql.proc                                         OK
mysql.procs_priv                                   OK
mysql.proxies_priv                                 OK
mysql.server_cost                                  OK
mysql.servers                                      OK
mysql.slave_master_info                            OK
mysql.slave_relay_log_info                         OK
mysql.slave_worker_info                            OK
mysql.slow_log                                     OK
mysql.tables_priv                                  OK
mysql.time_zone                                    OK
mysql.time_zone_leap_second                        OK
mysql.time_zone_name                               OK
mysql.time_zone_transition                         OK
mysql.time_zone_transition_type                    OK
mysql.user                                         OK
Found outdated sys schema version 1.4.0.
Upgrading the sys schema.
Checking databases.
ADMIN.T_ADMIN01                                    OK
REPLI.T_REPLI01                                    OK
REPLI.T_REPLI02                                    OK
sys.sys_config                                     OK
Upgrade process completed successfully.
Checking if update is needed.
[root@misc02 bin]# 

Proxy User, Replication機能などが増加しているので、
設定変数がまた増えているので、必要に応じて確認しておいた方が良さそうです。


root@localhost [mysql]> select @@version;
+------------------------------------------+
| @@version                                |
+------------------------------------------+
| 5.7.9-enterprise-commercial-advanced-log |
+------------------------------------------+
1 row in set (0.00 sec)

root@localhost [mysql]> 


root@localhost [mysql]> show variables;

<省略>
504 rows in set (0.01 sec)

root@localhost [mysql]> 

既に、幾つかのパラメータは設定変更してあります。

[root@misc02 ~]# mysqld --no-defaults --verbose --help | grep default-password-lifetime
  --default-password-lifetime=# 
default-password-lifetime                                    360
[root@misc02 ~]# cat /etc/my.cnf | grep default_password_lifetime
default_password_lifetime      = 0
[root@misc02 ~]# 
root@localhost [mysql]> select user,host,password_expired,password_last_changed from mysql.user;
+-----------+--------------+------------------+-----------------------+
| user      | host         | password_expired | password_last_changed |
+-----------+--------------+------------------+-----------------------+
| root      | localhost    | N                | 2015-04-25 17:39:01   |
| admin     | 192.168.56.% | N                | 2015-08-12 15:23:52   |
| admin     | localhost    | N                | 2015-08-12 15:24:29   |
| mysql.sys | localhost    | N                | 2015-10-22 07:12:48   |
+-----------+--------------+------------------+-----------------------+
4 rows in set (0.00 sec)

GAがリリースされたばかりなので、RCとの違いを確認しつつ安定運用のサポートしたいと思います。
Have a fun!!


MySQL5.7において、JSON(JavaScript Object Notation)がサポートされていて、
様々な言語やアプリ間で、より簡単にデータの受け渡しが行えるようになりました。
ドキュメントをJSONフォーマットでデータベースに保存して、
様々なアプリケーションから呼び出して利用出来るなど、
汎用性と運用面での活用が出来るようになっています。

1) ネイティブのJSONデータ型
効率的なデータ処理と保管にネイティブ内部バイナリ形式をサポート。
2) 組み込みJSONファンクション
効率よくドキュメントを保存,検索,更新,操作する事を可能にします。
3) JSON コンパレーター
文書データを容易にSQLクエリと統合することが可能
4) Generated Columnsを利用し、ドキュメントにインデックスを利用する事が可能。
新しいアナライザーは,自動的に利用可能で最適な機能インデックスを利用。

ファンクションの詳細は、こちらを参照してください。
12.16 JSON Functions

検証バージョン


root@localhost [USER01]> select @@version;
+--------------+
| @@version    |
+--------------+
| 5.7.8-rc-log |
+--------------+
1 row in set (0.00 sec)

検証用テーブル


root@localhost [USER01]> show create table T_JSON\G
*************************** 1. row ***************************
       Table: T_JSON
Create Table: CREATE TABLE `T_JSON` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `body` json DEFAULT NULL,
  `WithTax` decimal(10,2) GENERATED ALWAYS AS (json_extract(body,'$.price')*1.08) VIRTUAL,
  PRIMARY KEY (`id`),
  KEY `idx_total_cost_v` (`WithTax`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

root@localhost [USER01]> 

※WithTaxは、MySQL5.7から利用可能なGenerated Columnsで作成して、
 文書内のデータからインデックスを作成出来るようにしています。
 ここでは、文書からpriceを抜き出して、TAXを含むコストをベースにインデックスを作成しています。

テストデータ


root@localhost [USER01]> INSERT INTO T_JSON(body) VALUES ('{"id":1,"name":"自転車","price":10000,"Conditions":["NEW",2015]}');
Query OK, 1 row affected (0.15 sec)

root@localhost [USER01]> INSERT INTO T_JSON(body) VALUES ('{"id":2,"name":"TV","price":30000,"Conditions":["USED",2013]}');
Query OK, 1 row affected (0.01 sec)

root@localhost [USER01]> INSERT INTO T_JSON(body) VALUES ('{"id":3,"name":"冷蔵庫","price":50000,"Conditions":["NEW",2015]}');
Query OK, 1 row affected (0.00 sec)

root@localhost [USER01]> INSERT INTO T_JSON(body) VALUES ('{"id":4,"name":"冷蔵庫","price":50000,"Conditions":["NEW",2015]}');
Query OK, 1 row affected (0.00 sec)

root@localhost [USER01]> INSERT INTO T_JSON(body) VALUES ('{"id":5,"name":"自転車","price":25000,"Conditions":["NEW",2015]}');
Query OK, 1 row affected (0.01 sec)

<SNIP>

JSONデータ型で作成した列に、データをINSERTする時にフォーマットが正しいかバリデーションしてくれます。
間違えていると以下のようにエラーになります。


root@localhost [USER01]> INSERT INTO T_JSON(body) VALUES ('{"id":6,"name":"冷蔵庫","price":50000,"Conditions":["NEW",2015]');
ERROR 3140 (22032): Invalid JSON text: "Missing a comma or '}' after an object member." at position 66 in value (or column) '{"id":6,"name":"冷蔵庫","price":50000,"Conditions":["NEW",2015]'.
root@localhost [USER01]> 

データの参照


root@localhost [USER01]> select * from T_JSON;
+----+-----------------------------------------------------------------------------+----------+
| id | body                                                                        | WithTax  |
+----+-----------------------------------------------------------------------------+----------+
|  1 | {"id": 1, "name": "自転車", "price": 10000, "Conditions": ["NEW", 2015]}    | 10800.00 |
|  2 | {"id": 2, "name": "TV", "price": 30000, "Conditions": ["USED", 2013]}       | 32400.00 |
|  3 | {"id": 3, "name": "冷蔵庫", "price": 50000, "Conditions": ["NEW", 2015]}    | 54000.00 |
|  4 | {"id": 4, "name": "冷蔵庫", "price": 50000, "Conditions": ["NEW", 2015]}    | 54000.00 |
|  5 | {"id": 5, "name": "自転車", "price": 25000, "Conditions": ["NEW", 2015]}    | 27000.00 |
+----+-----------------------------------------------------------------------------+----------+
5 rows in set (0.01 sec)

root@localhost [USER01]> SELECT json_extract(body,'$.name') FROM T_JSON;
+-----------------------------+
| json_extract(body,'$.name') |
+-----------------------------+
| "自転車"                    |
| "TV"                        |
| "冷蔵庫"                    |
| "冷蔵庫"                    |
| "自転車"                    |
+-----------------------------+
5 rows in set (0.00 sec)

root@localhost [USER01]> 

select

該当のデータを含むデータの抽出例 (json_search())等。


root@localhost [USER01]> SELECT json_extract(body,'$.name')="自転車" FROM T_JSON;
+-----------------------------------------+
| json_extract(body,'$.name')="自転車"    |
+-----------------------------------------+
|                                       1 |
|                                       0 |
|                                       0 |
|                                       0 |
|                                       1 |
+-----------------------------------------+
5 rows in set (0.00 sec)

root@localhost [USER01]> SELECT id,json_search(body,'one','%自転車%') FROM T_JSON;
+----+---------------------------------------+
| id | json_search(body,'one','%自転車%')    |
+----+---------------------------------------+
|  1 | "$.name"                              |
|  2 | NULL                                  |
|  3 | NULL                                  |
|  4 | NULL                                  |
|  5 | "$.name"                              |
+----+---------------------------------------+
5 rows in set (0.00 sec)

root@localhost [USER01]> SELECT json_extract(body,'$.name') 
    -> FROM T_JSON where json_extract(body,'$.name') = '自転車';
+-----------------------------+
| json_extract(body,'$.name') |
+-----------------------------+
| "自転車"                    |
| "自転車"                    |
+-----------------------------+
2 rows in set (0.00 sec)

root@localhost [USER01]> 

JONS_WHERE

Generated Columnにインデックスを張ってあるので、インデックスを使用したドキュメントの検索の確認。


root@localhost [USER01]> SELECT json_extract(body,'$.name') FROM T_JSON where json_extract(body,'$.price') > 40000;
+-----------------------------+
| json_extract(body,'$.name') |
+-----------------------------+
| "冷蔵庫"                    |
| "冷蔵庫"                    |
+-----------------------------+
2 rows in set (0.00 sec)

root@localhost [USER01]> SELECT json_extract(body,'$.name') FROM T_JSON where WithTax > 40000;
+-----------------------------+
| json_extract(body,'$.name') |
+-----------------------------+
| "冷蔵庫"                    |
| "冷蔵庫"                    |
+-----------------------------+
2 rows in set (0.00 sec)

root@localhost [USER01]> explain SELECT json_extract(body,'$.name') FROM T_JSON where json_extract(body,'$.price') > 40000;
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | T_JSON | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    5 |   100.00 | Using where |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

root@localhost [USER01]> explain SELECT json_extract(body,'$.name') FROM T_JSON where WithTax > 40000;
+----+-------------+--------+------------+-------+------------------+------------------+---------+------+------+----------+-------------+
| id | select_type | table  | partitions | type  | possible_keys    | key              | key_len | ref  | rows | filtered | Extra       |
+----+-------------+--------+------------+-------+------------------+------------------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | T_JSON | NULL       | range | idx_total_cost_v | idx_total_cost_v | 6       | NULL |    2 |   100.00 | Using where |
+----+-------------+--------+------------+-------+------------------+------------------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

root@localhost [USER01]> 

index

【アップデート】

MySQL5.7 JSONデータ型とTEXTデータ型の比較

JSONデータとGenerated_Columnを使う場合の考慮事項

MySQL JSONデータ型とJSON関数の復習

参考:
12.16 JSON Functions
https://dev.mysql.com/doc/refman/5.7/en/json-functions.html

JSON Labs Release: Effective Functional Indexes in InnoDB
http://mysqlserverteam.com/json-labs-release-effective-functional-indexes-in-innodb/

MySQL and PostgreSQL JSON functions: do they differ much?
https://blogs.oracle.com/svetasmirnova/entry/mysql_and_postgresql_json_functions

JSON Labs Release: Effective Functional Indexes in InnoDB
http://mysqlserverteam.com/json-labs-release-effective-functional-indexes-in-innodb/


MySQL5.7.7RCの次のリリース、MySQL5.7.8が8月3日にリリースされました。
多くの機能追加や変更が行われています。RCの次のリリースですが、GAでは無いのでRC2という事になるかと思います。
RCにしては、少々機能追加が多いかと思いますが、色々と便利な機能が追加されています。
詳細は、以下のURLを参照下さい。

Changes in MySQL 5.7.8 (2015-08-03)
http://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-8.html

—————————————
Backup Notes
Configuration Notes
JSON Notes
Optimizer Notes
Packaging Notes
Performance Schema Notes
Plugin Notes
Security Notes
Spatial Data Support
SQL Mode Notes
Functionality Added or Changed
Bugs Fixed

本日は、MySQL5.6.26とMySQL5.7.8のパラメータの違いを確認してみました。
パラメータの拡張、新規パラメータの追加があります。

【パラメータの変更については、こちらを参照下さい。】
binlog_error_action
binlog_format
binlog_gtid_simple_recovery
eq_range_index_dive_limit
innodb_buffer_pool_dump_at_shutdown
その他。。。
change

変更されたパタメータを取りまとめた資料
MySQL5.7.8における変更されたパラメータ(pdf)

【新規追加されたパラメータについては此方を参照下さい。】
binlog_group_commit_sync_delay
binlog_group_commit_sync_no_delay_count
check_proxy_users
default_authentication_plugin
default_password_lifetime
その他。。。
new

新規追加されたパラメータ簡易取りまとめPDF
MySQL5.7.8において、新規追加されたパラメータ(pdf)

※新規追加されたパラメータに関しては、一部、Defaultの値から変更しています。
 Default値の確認は、5.1.4 Server System Variables を参照してください。

その他、以下のパラメータ等は、Removeされているようでした。
———————————————————
binlogging_impossible_mode
innodb_additional_mem_pool_size
innodb_mirrored_log_groups
innodb_use_sys_malloc
sha256_password_private_key_path
sha256_password_public_key_path
simplified_binlog_gtid_recovery
storage_engine
thread_concurrency
timed_mutexes

その他参考
Improved Server Defaults in 5.7

此方で5.7GA版と5.6のパラメータ比較資料がダウンロード可能です。
http://downloads.mysql.com/presentations/20151030_05_MySQL-Parameter-comparison.pdf


オンラインで色々なDDL処理が出来るのは、サービス提供側も、利用者も、DBAとしても
非常に便利な機能かと思います。MySQLは4.1からUnicode対応していたので、
10年弱程利用してますが、Online DDLが利用可能になるまでは、
夜中のユーザーが少ない時間にテーブル定義を変更していたりする事も多々ありました。
MySQL5.6以降のオンラインDDLはそういったメンテナンス対応の方には、非常に便利で有難い機能かと思います。

オンライン処理可能かどうかは、14.11.1. オンライン DDL の概要で確認する事が出来ます。
手元で簡単に確認したい場合は、以下のオプションで処理を指定して確認する事が可能です。

ALGORITHM=INPLACE
ALGORITHM=COPY

インプレース DDL 操作とテーブルコピー DDL 操作のパフォーマンスの比較
オンライン DDL 操作の raw パフォーマンスは、その操作がインプレースで実行されるか、
またはテーブル全体のコピーと再構築が必要かによってほとんど決定されます。
インプレースで実行できる操作の種類や、テーブルコピー操作を行わないための
何らかの要件を確認するには、表14.5「DDL 操作のオンラインステータスのサマリー」を参照してください。

例)これは5.7の場合(varcharサイズ変更)


ALTER TABLE T_ONLINE_DDL ALGORITHM=INPLACE, CHANGE COLUMN text text VARCHAR(255);

※ オンライン DDL のロックオプション
LOCK=EXCLUSIVE 
クエリーと DML 操作の両方がブロックされます。
LOCK=SHARED
DDL 操作では、テーブルへの書き込みがすべてブロックされますが、
そのテーブル内のデータは読み取ることができます。
LOCK=NONE
DDL 操作では、クエリーと並列 DML の両方が許可されます。
LOCK=DEFAULT
LOCK 句が省略された DDL 操作では、MySQL はその種類の操作で
使用可能なもっとも低いレベルのロックを使用することにより、
可能な場合は常に並列クエリー、DML、またはその両方を許可します。

参照:
14.11.2. オンライン DDL でのパフォーマンスと並列性に関する考慮事項

参照:MySQL5.7におけるオンライン処理の拡張
Online ALTER TABLE Enhance Varchar Size

オンライン DDL
DDL (主に ALTER TABLE) 操作中の InnoDB テーブルのパフォーマンス、並列性、および可用性を改善する機能。
詳細は、操作の種類に応じて異なります。場合によっては、ALTER TABLE の進行中にテーブルを同時に変更できます。この操作はテーブルコピーを行わずに、または特別に最適化されたタイプのテーブルコピーを使用せずに実行できる場合があります。
領域の使用量は、innodb_online_alter_log_max_size 構成オプションで制御されます。

innodb_online_alter_log_max_sizeに関しては、こちらの資料が参考になります。
https://www.percona.com/live/mysql-conference-2014/sites/default/files/slides/Online%20schema%20changes%20for%20maximizing%20uptime.pdf

——————————————————————————————-
抜粋:
14.11. InnoDB とオンライン DDL

——————————————————————————————-
MySQL 5.6 で導入されたオンライン DDL 機能は、ほかのタイプの多くの ALTER TABLE 操作を、
テーブルコピー、DDL が進行中の DML 操作のブロック化、またはその両方を行わないように拡張しています。

オンライン DDL 機能には、次の利点があります。
1)インデックスやカラム定義を変更する場合は常に、テーブルを数分または数時間にわたって使用できなくすることが現実的でないビジー状態の本番環境での応答性と可用性を向上させます。
2)テーブルへのアクセスを完全にブロックするか (LOCK=EXCLUSIVE 句)、クエリーを許可するが、
DML は許可しないか (LOCK=SHARED 句)、またはテーブルへの完全なクエリーおよび DML アクセスを許可するか (LOCK=NONE 句)どうかを選択することによって、DDL 操作中のパフォーマンスと並列性のバランスを調整できます。
3)LOCK 句を省略するか、または LOCK=DEFAULT を指定すると、MySQL は、操作の種類に応じてできるだけ高い並列性を許可します。
4)テーブルの新しいコピーを作成するのではなく、可能な場合はインプレースで変更を行うことによって、
テーブルのコピーおよびすべてのセカンダリインデックスの再構築のためのディスク領域の使用量やI/O オーバーヘッドの一時的な増加が回避されます。
——————————————————————————————-

本日は、ALTER TABLEにてストレージエンジンをINNODBに変換する場合の挙動について確認してみます。

MySQL 5.6.17 の時点では、ALTER TABLE tbl_name ENGINE=INNODB とALTER TABLE tbl_name FORCE の両方が
オンライン DDL (ALGORITHM=COPY) を使用します。
http://dev.mysql.com/doc/refman/5.6/ja/alter-table.html

ALGORITHM=COPY に 関する注意
ALGORITHM=COPY 句で実行 される ALTER TABLE 操作はすべて、並列 DML 操 作を妨げます。
並列クエリーは、引き続き許可されます。つま り、テーブルコピー操作には常に、
少なくとも LOCK=SHARED (クエリーを許可するが、DML は許 可しない) の並列性 の制限が含まれます。

初期設定確認


root@localhost [test]> select @@version;
+-------------------------------------------+
| @@version                                 |
+-------------------------------------------+
| 5.6.24-enterprise-commercial-advanced-log |
+-------------------------------------------+
1 row in set (0.00 sec)

root@localhost [test]> show variables like '%old_alter_table%';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| old_alter_table | OFF   |
+-----------------+-------+
1 row in set (0.00 sec)


以下、オンラインでの変更可否の確認
INPLACEを明示的に指定して、ストレージエンジンを変換してますが、処理がエラーになっています。
COPYでは問題無く終了しています。LOCKもSHAREDで無ければ許可されません。

root@localhost [USER01]> select TABLE_SCHEMA,TABLE_NAME,ENGINE from information_schema.TABLES where TABLE_SCHEMA = 'USER01' and TABLE_NAME = 'T_STORAGE_CONV';
+--------------+----------------+--------+
| TABLE_SCHEMA | TABLE_NAME     | ENGINE |
+--------------+----------------+--------+
| USER01       | T_STORAGE_CONV | MyISAM |
+--------------+----------------+--------+
1 row in set (0.00 sec)

root@localhost [USER01]> ALTER TABLE T_STORAGE_CONV ALGORITHM=INPLACE, ENGINE=InnoDB;
ERROR 1845 (0A000): ALGORITHM=INPLACE is not supported for this operation. Try ALGORITHM=COPY. 

root@localhost [test]> ALTER TABLE T_STORAGE_CONV ALGORITHM=COPY,LOCK=NONE,ENGINE=InnoDB;
ERROR 1846 (0A000): LOCK=NONE is not supported. Reason: COPY algorithm requires a lock. Try LOCK=SHARED.

root@localhost [USER01]> ALTER TABLE T_STORAGE_CONV ALGORITHM=COPY, ENGINE=InnoDB;
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

root@localhost [USER01]> select TABLE_SCHEMA,TABLE_NAME,ENGINE from information_schema.TABLES where TABLE_SCHEMA = 'USER01' and TABLE_NAME = 'T_STORAGE_CONV';
+--------------+----------------+--------+
| TABLE_SCHEMA | TABLE_NAME     | ENGINE |
+--------------+----------------+--------+
| USER01       | T_STORAGE_CONV | InnoDB |
+--------------+----------------+--------+
1 row in set (0.00 sec)

root@localhost [USER01]> 

SHAREDロックになってしまう処理
データを3件入れて、変換してみると3行程影響を受けている事が確認出来ます。
こにより、テーブルがCOPYされている事が確認出来ます。

root@localhost [test]> CREATE TABLE `T_STORAGE_CONV` (
    ->   `ID` int(11) NOT NULL AUTO_INCREMENT,
    ->   `MEMO` char(255) DEFAULT NULL,
    ->   PRIMARY KEY (`ID`)
    -> ) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
Query OK, 0 rows affected (0.01 sec)

root@localhost [test]> insert into T_STORAGE_CONV(MEMO) values('TEST ONLINE DDL 1');
Query OK, 1 row affected (0.00 sec)

root@localhost [test]> insert into T_STORAGE_CONV(MEMO) values('TEST ONLINE DDL 2');
Query OK, 1 row affected (0.00 sec)

root@localhost [test]> insert into T_STORAGE_CONV(MEMO) values('TEST ONLINE DDL 3');
Query OK, 1 row affected (0.00 sec)

root@localhost [test]> ALTER TABLE T_STORAGE_CONV ALGORITHM=COPY,LOCK=SHARED,ENGINE=InnoDB;
Query OK, 3 rows affected (0.04 sec)
Records: 3  Duplicates: 0  Warnings: 0

root@localhost [test]> 

Secondaryインデックスの追加や列の追加はONLINE出来る。
rows affectedの値が0であることからも確認出来る。

root@localhost [test]> ALTER TABLE T_STORAGE_CONV ALGORITHM=INPLACE,ADD INDEX IDX_MEMO(MEMO);                       
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

root@localhost [test]> show create table T_STORAGE_CONV\G
*************************** 1. row ***************************
       Table: T_STORAGE_CONV
Create Table: CREATE TABLE `T_STORAGE_CONV` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `MEMO` char(100) DEFAULT NULL,
  PRIMARY KEY (`ID`),
  KEY `IDX_MEMO` (`MEMO`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4
1 row in set (0.01 sec)

root@localhost [test]> desc T_STORAGE_CONV;
+-------+-----------+------+-----+---------+----------------+
| Field | Type      | Null | Key | Default | Extra          |
+-------+-----------+------+-----+---------+----------------+
| ID    | int(11)   | NO   | PRI | NULL    | auto_increment |
| MEMO  | char(100) | YES  | MUL | NULL    |                |
+-------+-----------+------+-----+---------+----------------+
2 rows in set (0.01 sec)

root@localhost [test]> ALTER TABLE T_STORAGE_CONV ALGORITHM=INPLACE,
    -> ADD CATEGORY varchar(10) after ID;
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0

root@localhost [test]> desc T_STORAGE_CONV;
+----------+-------------+------+-----+---------+----------------+
| Field    | Type        | Null | Key | Default | Extra          |
+----------+-------------+------+-----+---------+----------------+
| ID       | int(11)     | NO   | PRI | NULL    | auto_increment |
| CATEGORY | varchar(10) | YES  |     | NULL    |                |
| MEMO     | char(100)   | YES  | MUL | NULL    |                |
+----------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

root@localhost [test]> 

ONLINE_DDL

マニュアルにも載っているが、もしオンラインで処理可能か?もしくはDMLがブロックされるかどうか不明な場合は、
上記のようにオプションを付けて確認して見る事も可能です。

参考: 14.11.1. オンライン DDL の概要


MySQLのmysqlbinlogコマンドでは、MySQL5.6からリモートにあるバイナリーログを読み取る事が可能になりましたが、SSLを利用した通信の暗号化はサポートされておりませんでした。

次期メジャーバージョンのMySQL5.7では、ここら辺も機能拡張されておりmysqlbinlogコマンドを利用して、リモートのバイナリーログを読み込み場合にもSSLを利用した通信の暗号化を行う事が出来るようになりました。
Firewall、セキュリティ機器、セグメント分割された環境で、何処まで必要になるかは状況次第ですが、
リモートサーバーが自然災害対策の為に、自分でインフラを準備する必要が無いPublicクラウド上にある場合などに通信の暗号化が出来ると安心ですね。
※ MySQLのレプリケーションでは、以前からSSLを利用した通信の暗号化が可能です。

参照: 
MySQL 5.7: mysqlbinlog now supports SSL

MySQL5.7 mysqlbinlogマニュアル
4.6.7 mysqlbinlog — Utility for Processing Binary Log Files

MySQL5.6: mysqlbinlogコマンドでリモートデータベースからログを読みこむ機能の確認

4.6.8. mysqlbinlog — バイナリログファイルを処理するためのユーティリティー

[環境] リモートからのログ読み込み基本動作確認
MySQL: 5.6.24 (SSLの確認は別途)
remote-diag

特定ログファイルの読み込み

ログ取得元サーバー


[admin@GA01 ~]$ mysql -u root -p -e 'show master logs';
Enter password: 
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000117 |   1636700 |
| mysql-bin.000118 |       844 |
| mysql-bin.000119 |       222 |
| mysql-bin.000120 |       518 |
| mysql-bin.000121 |       470 |
| mysql-bin.000122 |       222 |
+------------------+-----------+
[admin@GA01 ~]$ ls -l /usr/local/mysql/data/mysql-bin.000117
-rw-rw----. 1 mysql mysql 1636700  7月  6 10:21 /usr/local/mysql/data/mysql-bin.000117
[admin@GA01 ~]$ 

ログ読み込みクライアントサーバー
ログが読みこまれているのが確認出来る。バイナリーのまま持ってくる場合は、
”–raw”オプションを付けてあげれば良い。


[admin@misc01 tmp]$ /usr/local/mysql/bin/mysqlbinlog --read-from-remote-server \
> --host=192.168.56.201 --user=admin --password  \
> mysql-bin.000117 > RemoteLogBackup_`date "+%Y%m%d_%H%M%S"`.sql
Enter password: 
[admin@misc01 tmp]$ ls -l
合計 3632
-rw-rw-r--. 1 admin admin 3715955  7月  9 11:06 RemoteLogBackup_20150709_110610.sql
[admin@misc01 tmp]$ cat RemoteLogBackup_20150709_110610.sql | grep CREATE
CREATE DATABASE `world` /*!40100 DEFAULT CHARACTER SET utf8 */
CREATE TABLE `City` (
CREATE TABLE `Country` (
CREATE TABLE `CountryLanguage` (
CREATE DATABASE `audit_information`  /*!40100 DEFAULT CHARACTER SET utf8 */
CREATE DATABASE `audit_information`  /*!40100 DEFAULT CHARACTER SET utf8mb4 */
CREATE TABLE `audit_parsed` (
CREATE TABLE `audit_history` (
[admin@misc01 tmp]$ 

binlogread

指定したログファイル以降のログも全て持ってくる場合


[admin@misc01 tmp]$ /usr/local/mysql/bin/mysqlbinlog --read-from-remote-server \
> --host=192.168.56.201 --user=admin --password  --to-last-log \
> mysql-bin.000117 > RemoteLogBackup_`date "+%Y%m%d_%H%M%S"`.sql
Enter password: 
[admin@misc01 tmp]$ ls -l
合計 7268
-rw-rw-r--. 1 admin admin 3715955  7月  9 11:06 RemoteLogBackup_20150709_110610.sql
-rw-rw-r--. 1 admin admin 3722407  7月  9 11:46 RemoteLogBackup_20150709_114625.sql
[admin@misc01 tmp]$ cat RemoteLogBackup_*.sql | grep CREATE
CREATE DATABASE `world` /*!40100 DEFAULT CHARACTER SET utf8 */
CREATE TABLE `City` (
CREATE TABLE `Country` (
CREATE TABLE `CountryLanguage` (
CREATE DATABASE `audit_information`  /*!40100 DEFAULT CHARACTER SET utf8 */
CREATE DATABASE `audit_information`  /*!40100 DEFAULT CHARACTER SET utf8mb4 */
CREATE TABLE `audit_parsed` (
CREATE TABLE `audit_history` (
CREATE DATABASE `world` /*!40100 DEFAULT CHARACTER SET utf8 */
CREATE TABLE `City` (
CREATE TABLE `Country` (
CREATE TABLE `CountryLanguage` (
CREATE DATABASE `audit_information`  /*!40100 DEFAULT CHARACTER SET utf8 */
CREATE DATABASE `audit_information`  /*!40100 DEFAULT CHARACTER SET utf8mb4 */
CREATE TABLE `audit_parsed` (
CREATE TABLE `audit_history` (
[admin@misc01 tmp]$ 


ログの中身を確認してみると、先頭行のポジションが同じである事が確認出来る。


[admin@misc01 tmp]$ cat RemoteLogBackup_20150709_110610.sql | grep \# | head 
# at 4
#290328 15:21:27 server id 1  end_log_pos 120 CRC32 0x3a600c07  Start: binlog v 4, server v 5.6.24-enterprise-commercial-advanced-log created 290328 15:21:27 at startup
# at 120
#290328 15:21:27 server id 1  end_log_pos 151 CRC32 0xe9d5507f  Previous-GTIDs
# [empty]
# at 151
#380119 12:14:09 server id 1  end_log_pos 222 CRC32 0x5aae6a2b  Previous-GTIDs
# 8560c2ac-e1dc-11e4-88ff-0800275399c1:1-612
# at 222
#150703 11:57:42 server id 1  end_log_pos 270 CRC32 0xb9607b03  GTID    last_committed=0        sequence_number=0

[admin@misc01 tmp]$ cat RemoteLogBackup_20150709_114625.sql | grep \# | head 
# at 4
#700101  9:00:00 server id 1  end_log_pos 0     Rotate to mysql-bin.000117  pos: 4
# at 4
#290328 15:21:27 server id 1  end_log_pos 120 CRC32 0x3a600c07  Start: binlog v 4, server v 5.6.24-enterprise-commercial-advanced-log created 290328 15:21:27 at startup
# at 120
#290328 15:21:27 server id 1  end_log_pos 151 CRC32 0xe9d5507f  Previous-GTIDs
# [empty]
# at 151
#380119 12:14:09 server id 1  end_log_pos 222 CRC32 0x5aae6a2b  Previous-GTIDs
# 8560c2ac-e1dc-11e4-88ff-0800275399c1:1-612
[admin@misc01 tmp]$ 

ログの中身を確認してみると、特定のログ以降の全てのログを読みこんだログは、
最終変更までのバイナリーログが読みこまれている事が確認出来る。

[admin@misc01 tmp]$ cat RemoteLogBackup_20150709_110610.sql | grep \# | tail -n 20
#150703 19:06:58 server id 1  end_log_pos 1634541 CRC32 0x49844ce7      GTID    last_committed=0        sequence_number=0
# at 1634541
#150703 19:06:58 server id 1  end_log_pos 1634716 CRC32 0x271b8e30      Query   thread_id=6     exec_time=0     error_code=0
# at 1634716
#150703 19:07:50 server id 1  end_log_pos 1634764 CRC32 0x92c5292d      GTID    last_committed=0        sequence_number=0
# at 1634764
#150703 19:07:50 server id 1  end_log_pos 1634875 CRC32 0x1b73a468      Query   thread_id=6     exec_time=0     error_code=0
# at 1634875
#150703 19:08:03 server id 1  end_log_pos 1634923 CRC32 0x62aa0722      GTID    last_committed=0        sequence_number=0
# at 1634923
#150703 19:08:03 server id 1  end_log_pos 1635101 CRC32 0x10ed801d      Query   thread_id=6     exec_time=0     error_code=0
# at 1635101
#150703 19:08:21 server id 1  end_log_pos 1635149 CRC32 0x805c979c      GTID    last_committed=0        sequence_number=0
# at 1635149
#150703 19:08:21 server id 1  end_log_pos 1636236 CRC32 0x78f51539      Query   thread_id=6     exec_time=0     error_code=0
# at 1636236
#150703 19:08:41 server id 1  end_log_pos 1636284 CRC32 0xf6128e4b      GTID    last_committed=0        sequence_number=0
# at 1636284
#150703 19:08:41 server id 1  end_log_pos 1636700 CRC32 0xeda14d3e      Query   thread_id=6     exec_time=0     error_code=0
# End of log file
[admin@misc01 tmp]$ cat RemoteLogBackup_20150709_114625.sql | grep \# | tail -n 20
# at 151
#380119 12:14:09 server id 1  end_log_pos 222 CRC32 0x1bbf07f9  Previous-GTIDs
# 8560c2ac-e1dc-11e4-88ff-0800275399c1:1-5933
# at 222
#150708 14:30:37 server id 1  end_log_pos 270 CRC32 0x7fdb0132  GTID    last_committed=0        sequence_number=0
# at 270
#150708 14:30:35 server id 1  end_log_pos 370 CRC32 0xdc99f8eb  Query   thread_id=1     exec_time=0     error_code=0
# at 370
#150708 14:30:35 server id 1  end_log_pos 470 CRC32 0xa8b91492  Query   thread_id=1     exec_time=0     error_code=0
# at 4
#700101  9:00:00 server id 1  end_log_pos 0 CRC32 0xc2515710    Rotate to mysql-bin.000122  pos: 4
# at 4
#700101  9:00:00 server id 1  end_log_pos 120 CRC32 0x07fa7f88  Start: binlog v 4, server v 5.6.24-enterprise-commercial-advanced-log created 700101  9:00:00
# at 120
#700101  9:00:00 server id 1  end_log_pos 151 CRC32 0x218282e8  Previous-GTIDs
# [empty]
# at 151
#380119 12:14:09 server id 1  end_log_pos 222 CRC32 0xd7150767  Previous-GTIDs
# 8560c2ac-e1dc-11e4-88ff-0800275399c1:1-5934
# End of log file
[admin@misc01 tmp]$ 

リモートデータベースからログを読み込み、定期的に遠隔地に保存してしておく方法の一つとしても使えそうです。


データ量が昔と比較して増えてきたからか、最近はパーティションの話を良く聞くので、
簡易的に再確認してみました。いざ確認してみると、色々と忘れている事もあり頭がリフレッシュ出来ました。
パーティショニン種類に関しては、以下のサイトに詳しく出ているので参照してみて下さい。
また、MySQL5.6のマニュアルも日本語化されたので参考にしてみて下さい。

MySQL5.6日本語マニュアル
https://dev.mysql.com/doc/refman/5.6/ja/

19.2. パーティショニングタイプ
https://dev.mysql.com/doc/refman/5.6/ja/partitioning-types.html

——————————————————————————————–
※奥野さんのサイトにも書かれていますが、必ずしもパーティションを利用して、
 パフォーマンスが良くなる事ばかりでは無いです。効率良くIndexが使えていたりデータによっては、
 付けない方が良い事もあるので、先ずは検証環境で確認してみて下さい。

 パーティショニングの使用例 – カーディナリティが低いカラムを使って検索する場合
 http://nippondanji.blogspot.jp/2009/04/1.html
——————————————————————————————–

第19章 パーティション化
https://dev.mysql.com/doc/refman/5.6/ja/partitioning.html

19.6. パーティショニングの制約と制限
https://dev.mysql.com/doc/refman/5.6/ja/partitioning-limitations.html#partitioning-limitations-subpartitions

確認:バージョン

root@localhost [test]> select @@version;
+-------------------------------------------+
| @@version                                 |
+-------------------------------------------+
| 5.6.24-enterprise-commercial-advanced-log |
+-------------------------------------------+
1 row in set (0.00 sec)

root@localhost [test]> 

プラグインで有効になっているか確認

root@localhost [test]> SELECT 
    -> PLUGIN_NAME as Name, 
    -> PLUGIN_VERSION as Version, 
    -> PLUGIN_STATUS as Status 
    -> FROM INFORMATION_SCHEMA.PLUGINS 
    -> WHERE PLUGIN_TYPE='STORAGE ENGINE';
+--------------------+---------+----------+
| Name               | Version | Status   |
+--------------------+---------+----------+
| binlog             | 1.0     | ACTIVE   |
| MEMORY             | 1.0     | ACTIVE   |
| MRG_MYISAM         | 1.0     | ACTIVE   |
| CSV                | 1.0     | ACTIVE   |
| MyISAM             | 1.0     | ACTIVE   |
| ARCHIVE            | 3.0     | ACTIVE   |
| FEDERATED          | 1.0     | DISABLED |
| InnoDB             | 5.6     | ACTIVE   |
| BLACKHOLE          | 1.0     | ACTIVE   |
| PERFORMANCE_SCHEMA | 0.1     | ACTIVE   |
| partition          | 1.0     | ACTIVE   | < --- こちらがACTIVEであれば利用可能
+--------------------+---------+----------+
11 rows in set (0.01 sec)

root@localhost [test]> 

■ 標準的なRANGEパーティショニング

root@localhost [test]> show create table tbl_partition\G
*************************** 1. row ***************************
       Table: tbl_partition
Create Table: CREATE TABLE `tbl_partition` (
  `member_id` varchar(40) NOT NULL,
  `platform` varchar(10) NOT NULL,
  `year` smallint(5) unsigned NOT NULL,
  `month` tinyint(2) unsigned NOT NULL,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`member_id`,`year`,`month`),
  KEY `idx_tbl_partition` (`year`),
  KEY `idx_tbl_partition_id` (`member_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
/*!50100 PARTITION BY RANGE (`year`)
(PARTITION p2013 VALUES LESS THAN (2013) ENGINE = InnoDB,
 PARTITION p2014 VALUES LESS THAN (2014) ENGINE = InnoDB,
 PARTITION p2015 VALUES LESS THAN (2015) ENGINE = InnoDB,
 PARTITION p2016 VALUES LESS THAN (2016) ENGINE = InnoDB,
 PARTITION p2017 VALUES LESS THAN (2017) ENGINE = InnoDB,
 PARTITION p2018 VALUES LESS THAN (2018) ENGINE = InnoDB,
 PARTITION p2019 VALUES LESS THAN (2019) ENGINE = InnoDB,
 PARTITION p2020 VALUES LESS THAN (2020) ENGINE = InnoDB,
 PARTITION pmax VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */
1 row in set (0.00 sec)

root@localhost [test]> 

root@localhost [test]> explain partitions select * from tbl_partition where year = 2015;
+----+-------------+---------------+------------+------+-------------------+-------------------+---------+-------+------+-------+
| id | select_type | table         | partitions | type | possible_keys     | key               | key_len | ref   | rows | Extra |
+----+-------------+---------------+------------+------+-------------------+-------------------+---------+-------+------+-------+
|  1 | SIMPLE      | tbl_partition | p2016      | ref  | idx_tbl_partition | idx_tbl_partition | 2       | const |    2 | NULL  |
+----+-------------+---------------+------------+------+-------------------+-------------------+---------+-------+------+-------+
1 row in set (0.00 sec)

root@localhost [test]> 

■ サブパーティション
https://dev.mysql.com/doc/refman/5.6/ja/partitioning-subpartitions.html

サブパーティションに関する問題
https://dev.mysql.com/doc/refman/5.6/ja/partitioning-limitations.html#partitioning-limitations-subpartitions

サブパーティションに関する問題 サブパーティションは HASH または KEY パーティショニングを使用する必要があります。サブパーティション化できるのは RANGE および LIST パーティションのみです。HASH および KEY パーティションはサブパーティション化できません。 現在のところ、SUBPARTITION BY KEY にはサブパーティショニングカラムを明示的に指定する必要がありますが、PARTITION BY KEY の場合は省略できます (その場合、テーブルの主キーカラムがデフォルトで使用されます)


root@localhost [test]> show create table tbl_sub_partition01\G
*************************** 1. row ***************************
       Table: tbl_sub_partition01
Create Table: CREATE TABLE `tbl_sub_partition01` (
  `member_id` int(11) DEFAULT NULL,
  `platform` varchar(10) NOT NULL,
  `purchased` date DEFAULT NULL,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
/*!50100 PARTITION BY RANGE ( YEAR(purchased))
SUBPARTITION BY HASH ( TO_DAYS(purchased))
SUBPARTITIONS 12
(PARTITION sub_y2010 VALUES LESS THAN (2010) ENGINE = InnoDB,
 PARTITION sub_y2011 VALUES LESS THAN (2011) ENGINE = InnoDB,
 PARTITION sub_y2012 VALUES LESS THAN (2012) ENGINE = InnoDB,
 PARTITION sub_y2013 VALUES LESS THAN (2013) ENGINE = InnoDB,
 PARTITION sub_y2014 VALUES LESS THAN (2014) ENGINE = InnoDB,
 PARTITION sub_y2015 VALUES LESS THAN (2015) ENGINE = InnoDB,
 PARTITION sub_y2016 VALUES LESS THAN (2016) ENGINE = InnoDB,
 PARTITION sub_y2017 VALUES LESS THAN (2017) ENGINE = InnoDB,
 PARTITION sub_y2018 VALUES LESS THAN (2018) ENGINE = InnoDB,
 PARTITION sub_y2019 VALUES LESS THAN (2019) ENGINE = InnoDB,
 PARTITION sub_y2020 VALUES LESS THAN (2020) ENGINE = InnoDB,
 PARTITION sub_y_max VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */
1 row in set (0.00 sec)

root@localhost [test]> 

timestamp型などを利用すると、
”ERROR 1486 (HY000): Constant, random or timezone-dependent expressions in (sub)partitioning function are not allowed”というエラーになります。

root@localhost [test]> select * from tbl_sub_partition01;
+-----------+----------+------------+---------------------+
| member_id | platform | purchased  | updated_at          |
+-----------+----------+------------+---------------------+
|         1 | iphone   | 2015-06-28 | 2015-06-30 11:53:32 |
|         2 | iphone   | 2015-06-29 | 2015-06-30 11:53:39 |
|         3 | iphone   | 2015-06-30 | 2015-06-30 11:53:47 |
|         4 | iphone   | 2015-07-01 | 2015-06-30 12:08:13 |
|         5 | iphone6  | 2015-07-02 | 2015-06-30 12:08:26 |
|         6 | iphone6  | 2015-07-03 | 2015-06-30 12:10:11 |
|         7 | iphone3s | 2015-07-04 | 2015-06-30 12:10:27 |
|         8 | iphone4s | 2015-07-05 | 2015-06-30 12:10:37 |
|         9 | iphone4s | 2015-07-06 | 2015-06-30 12:10:46 |
|        10 | iphone6s | 2015-07-07 | 2015-06-30 12:10:59 |
+-----------+----------+------------+---------------------+
10 rows in set (0.00 sec)

root@localhost [test]> explain partitions select * from tbl_sub_partition01 where purchased = '2015-07-01';
+----+-------------+---------------------+------------------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table               | partitions             | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+---------------------+------------------------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | tbl_sub_partition01 | sub_y2016_sub_y2016sp5 | ALL  | NULL          | NULL | NULL    | NULL |    2 | Using where |
+----+-------------+---------------------+------------------------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

root@localhost [test]> 

パーティションにDATA DIRECTORYなどを指定する場合。
MyISAMで且つ、テーブル全体では無くSubpartition毎に指定しています。

root@localhost [test]> show create table tbl_sub_partition_dir\G
*************************** 1. row ***************************
       Table: tbl_sub_partition_dir
Create Table: CREATE TABLE `tbl_sub_partition_dir` (
  `id` int(11) DEFAULT NULL,
  `purchased` date DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4
/*!50100 PARTITION BY RANGE ( YEAR(purchased))
SUBPARTITION BY HASH ( TO_DAYS(purchased))
(PARTITION p0_dir VALUES LESS THAN (1990)
 (SUBPARTITION s0 DATA DIRECTORY = '/home/mysql/data' INDEX DIRECTORY = '/home/mysql/index' ENGINE = MyISAM,
  SUBPARTITION s1 DATA DIRECTORY = '/home/mysql/data' INDEX DIRECTORY = '/home/mysql/index' ENGINE = MyISAM),
 PARTITION p1_dir VALUES LESS THAN (2000)
 (SUBPARTITION s2 DATA DIRECTORY = '/home/mysql/data' INDEX DIRECTORY = '/home/mysql/index' ENGINE = MyISAM,
  SUBPARTITION s3 DATA DIRECTORY = '/home/mysql/data' INDEX DIRECTORY = '/home/mysql/index' ENGINE = MyISAM),
 PARTITION p2_dir VALUES LESS THAN MAXVALUE
 (SUBPARTITION s4 DATA DIRECTORY = '/home/mysql/data' INDEX DIRECTORY = '/home/mysql/index' ENGINE = MyISAM,
  SUBPARTITION s5 DATA DIRECTORY = '/home/mysql/data' INDEX DIRECTORY = '/home/mysql/index' ENGINE = MyISAM)) */
1 row in set (0.01 sec)

root@localhost [test]> system ls /home/mysql/data/
tbl_sub_partition_dir#P#p0_dir#SP#s0.MYD  tbl_sub_partition_dir#P#p1_dir#SP#s2.MYD  tbl_sub_partition_dir#P#p2_dir#SP#s4.MYD  test
tbl_sub_partition_dir#P#p0_dir#SP#s1.MYD  tbl_sub_partition_dir#P#p1_dir#SP#s3.MYD  tbl_sub_partition_dir#P#p2_dir#SP#s5.MYD
root@localhost [test]> system ls /home/mysql/index/
tbl_sub_partition_dir#P#p0_dir#SP#s0.MYI  tbl_sub_partition_dir#P#p1_dir#SP#s2.MYI  tbl_sub_partition_dir#P#p2_dir#SP#s4.MYI
tbl_sub_partition_dir#P#p0_dir#SP#s1.MYI  tbl_sub_partition_dir#P#p1_dir#SP#s3.MYI  tbl_sub_partition_dir#P#p2_dir#SP#s5.MYI
root@localhost [test]> 

sub_myisam

DATAディレクトリーにシンボリックリンクが作成されています。

[root@GA01 test]# pwd
/usr/local/mysql/data/test
[root@GA01 test]# ls -l tbl_sub_partition_dir*
lrwxrwxrwx. 1 mysql mysql   57  6月 30 13:31 tbl_sub_partition_dir#P#p0_dir#SP#s0.MYD -> /home/mysql/data/tbl_sub_partition_dir#P#p0_dir#SP#s0.MYD
lrwxrwxrwx. 1 mysql mysql   58  6月 30 13:31 tbl_sub_partition_dir#P#p0_dir#SP#s0.MYI -> /home/mysql/index/tbl_sub_partition_dir#P#p0_dir#SP#s0.MYI
lrwxrwxrwx. 1 mysql mysql   57  6月 30 13:31 tbl_sub_partition_dir#P#p0_dir#SP#s1.MYD -> /home/mysql/data/tbl_sub_partition_dir#P#p0_dir#SP#s1.MYD
lrwxrwxrwx. 1 mysql mysql   58  6月 30 13:31 tbl_sub_partition_dir#P#p0_dir#SP#s1.MYI -> /home/mysql/index/tbl_sub_partition_dir#P#p0_dir#SP#s1.MYI
lrwxrwxrwx. 1 mysql mysql   57  6月 30 13:31 tbl_sub_partition_dir#P#p1_dir#SP#s2.MYD -> /home/mysql/data/tbl_sub_partition_dir#P#p1_dir#SP#s2.MYD
lrwxrwxrwx. 1 mysql mysql   58  6月 30 13:31 tbl_sub_partition_dir#P#p1_dir#SP#s2.MYI -> /home/mysql/index/tbl_sub_partition_dir#P#p1_dir#SP#s2.MYI
lrwxrwxrwx. 1 mysql mysql   57  6月 30 13:31 tbl_sub_partition_dir#P#p1_dir#SP#s3.MYD -> /home/mysql/data/tbl_sub_partition_dir#P#p1_dir#SP#s3.MYD
lrwxrwxrwx. 1 mysql mysql   58  6月 30 13:31 tbl_sub_partition_dir#P#p1_dir#SP#s3.MYI -> /home/mysql/index/tbl_sub_partition_dir#P#p1_dir#SP#s3.MYI
lrwxrwxrwx. 1 mysql mysql   57  6月 30 13:31 tbl_sub_partition_dir#P#p2_dir#SP#s4.MYD -> /home/mysql/data/tbl_sub_partition_dir#P#p2_dir#SP#s4.MYD
lrwxrwxrwx. 1 mysql mysql   58  6月 30 13:31 tbl_sub_partition_dir#P#p2_dir#SP#s4.MYI -> /home/mysql/index/tbl_sub_partition_dir#P#p2_dir#SP#s4.MYI
lrwxrwxrwx. 1 mysql mysql   57  6月 30 13:31 tbl_sub_partition_dir#P#p2_dir#SP#s5.MYD -> /home/mysql/data/tbl_sub_partition_dir#P#p2_dir#SP#s5.MYD
lrwxrwxrwx. 1 mysql mysql   58  6月 30 13:31 tbl_sub_partition_dir#P#p2_dir#SP#s5.MYI -> /home/mysql/index/tbl_sub_partition_dir#P#p2_dir#SP#s5.MYI
-rw-rw----. 1 mysql mysql 8596  6月 30 13:31 tbl_sub_partition_dir.frm
-rw-rw----. 1 mysql mysql  104  6月 30 13:31 tbl_sub_partition_dir.par
[root@GA01 test]# 

data foler

19.6.4. パーティショニングとロック
https://dev.mysql.com/doc/refman/5.6/ja/partitioning-limitations-locking.html

MySQL 5.6.6 はパーティションロックプルーニングを実装し、これによって多くの場合に不必要なロックが排除されます。
MySQL 5.6.6 以降では、パーティション化された MyISAM テーブルに対して読み取りまたは更新を行うほとんどのステートメントで、影響を受けるパーティションのみがロックされます。たとえば、MySQL 5.6.6 より前は、パーティション化 MyISAM テーブルからのSELECT でテーブル全体がロックされました。MySQL 5.6.6 以降は、SELECT ステートメントの WHERE 条件を満たす行を実際に含むパーティションのみがロックされます。これには、パーティション化された MyISAM テーブルに対する同時操作の速度および効率を向上させる効果があります。この改善は、多く (32 以上) のパーティションを持つ MyISAM テーブルを操作するときに特に顕著になります。

DATA DIRECTORY、INDEX DIRECTORY
http://dev.mysql.com/doc/refman/5.6/ja/create-table.html

InnoDB では、DATA DIRECTORY=’directory’ オプションを使用すると、MySQL データディレクトリ以外の場所に新しいInnoDB file-per-table テーブルスペースを作成できます。MySQL は、指定されたディレクトリ内にデータベース名に対応するサブディレクトリを作成し、さらにその中に新しいテーブルの .ibd ファイルを作成します。InnoDB テーブルで DATA DIRECTORY オプションを使用するには、innodb_file_per_table 構成オプションを有効にする必要があります。このディレクトリは、ディレクトリへの (相対パスではなく) フルパス名である必要があります。
詳細は、「テーブルスペースの位置の指定」を参照してください。
MyISAM テーブルを作成する場合は、DATA DIRECTORY=’directory’ 句、INDEX DIRECTORY=’directory’ 句、またはその両方を使用できます。これらは、それぞれ MyISAM テーブルのデータファイルとインデックスファイルを配置する場所を指定します。
InnoDB テーブルとは異なり、DATA DIRECTORY または INDEX DIRECTORY オプションで MyISAM テーブルを作成する場合、MySQL はデータベース名に対応するサブディレクトリを作成しません。各ファイルは、指定されたディレクトリ内に作成されます。

重要
https://bugs.mysql.com/bug.php?id=32091
テーブルレベルの DATA DIRECTORY および INDEX DIRECTORY オプションは、パーティション化されたテーブルでは無視されます。(Bug #32091)

■InnoDBで、SUBPARTITIONを指定せずに実行した場合


root@localhost [test]> CREATE TABLE `tbl_partition_innodb` (
    ->   `member_id` varchar(40) NOT NULL,
    ->   `platform` varchar(10) NOT NULL,
    ->   `year` smallint(5) unsigned NOT NULL,
    ->   `month` tinyint(2) unsigned NOT NULL,
    ->   `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
    ->   PRIMARY KEY (`member_id`,`year`,`month`),
    ->   KEY `idx_tbl_partition` (`year`),
    ->   KEY `idx_tbl_partition_id` (`member_id`)
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DATA DIRECTORY = '/home/mysql/data';
Query OK, 0 rows affected (0.02 sec)

root@localhost [test]> show create table tbl_partition_innodb\G
*************************** 1. row ***************************
       Table: tbl_partition_innodb
Create Table: CREATE TABLE `tbl_partition_innodb` (
  `member_id` varchar(40) NOT NULL,
  `platform` varchar(10) NOT NULL,
  `year` smallint(5) unsigned NOT NULL,
  `month` tinyint(2) unsigned NOT NULL,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`member_id`,`year`,`month`),
  KEY `idx_tbl_partition` (`year`),
  KEY `idx_tbl_partition_id` (`member_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DATA DIRECTORY='/home/mysql/data/'
1 row in set (0.00 sec)

ALTERテーブルでパーティション化すると、DATA DIRECTORYは無効になりファイルは削除されます。

root@localhost [test]> Alter table tbl_partition_innodb PARTITION BY RANGE (`year`)
    -> (PARTITION p2013_innodb VALUES LESS THAN (2013) ENGINE = InnoDB,
    ->  PARTITION p2014_innodb VALUES LESS THAN (2014) ENGINE = InnoDB,
    ->  PARTITION p2015_innodb VALUES LESS THAN (2015) ENGINE = InnoDB,
    ->  PARTITION p2016_innodb VALUES LESS THAN (2016) ENGINE = InnoDB,
    ->  PARTITION p2017_innodb VALUES LESS THAN (2017) ENGINE = InnoDB,
    ->  PARTITION p2018_innodb VALUES LESS THAN (2018) ENGINE = InnoDB,
    ->  PARTITION p2019_innodb VALUES LESS THAN (2019) ENGINE = InnoDB,
    ->  PARTITION p2020_innodb VALUES LESS THAN (2020) ENGINE = InnoDB,
    ->  PARTITION pmax_innodb VALUES LESS THAN MAXVALUE ENGINE = InnoDB) ;
Query OK, 0 rows affected (0.09 sec)
Records: 0  Duplicates: 0  Warnings: 0

root@localhost [test]> show create table tbl_partition_innodb\G
*************************** 1. row ***************************
       Table: tbl_partition_innodb
Create Table: CREATE TABLE `tbl_partition_innodb` (
  `member_id` varchar(40) NOT NULL,
  `platform` varchar(10) NOT NULL,
  `year` smallint(5) unsigned NOT NULL,
  `month` tinyint(2) unsigned NOT NULL,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`member_id`,`year`,`month`),
  KEY `idx_tbl_partition` (`year`),
  KEY `idx_tbl_partition_id` (`member_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
/*!50100 PARTITION BY RANGE (`year`)
(PARTITION p2013_innodb VALUES LESS THAN (2013) ENGINE = InnoDB,
 PARTITION p2014_innodb VALUES LESS THAN (2014) ENGINE = InnoDB,
 PARTITION p2015_innodb VALUES LESS THAN (2015) ENGINE = InnoDB,
 PARTITION p2016_innodb VALUES LESS THAN (2016) ENGINE = InnoDB,
 PARTITION p2017_innodb VALUES LESS THAN (2017) ENGINE = InnoDB,
 PARTITION p2018_innodb VALUES LESS THAN (2018) ENGINE = InnoDB,
 PARTITION p2019_innodb VALUES LESS THAN (2019) ENGINE = InnoDB,
 PARTITION p2020_innodb VALUES LESS THAN (2020) ENGINE = InnoDB,
 PARTITION pmax_innodb VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */
1 row in set (0.00 sec)

root@localhost [test]> 

※ Alter Tableでパーティショニングすると、
  DATA DIRECTORY=’/home/mysql/data/’に存在していたibdファイルは削除されます。

file_innodb_alter_update

■圧縮テーブルとパーティショニング
パーティション毎にストレージエンジンンが指定出来ますが、圧縮はパーティション毎に指定出来ません。
圧縮する場合はテーブル毎に指定してください。

root@localhost [test]> show create table tbl_partition_sample_zip\G
*************************** 1. row ***************************
       Table: tbl_partition_sample_zip
Create Table: CREATE TABLE `tbl_partition_sample_zip` (
  `member_id` varchar(40) NOT NULL,
  `platform` varchar(10) NOT NULL,
  `year` smallint(5) unsigned NOT NULL,
  `month` tinyint(2) unsigned NOT NULL,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`member_id`,`year`,`month`),
  KEY `idx_tbl_partition` (`year`),
  KEY `idx_tbl_partition_id` (`member_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4
/*!50100 PARTITION BY RANGE (`year`)
(PARTITION p2013 VALUES LESS THAN (2013) ENGINE = InnoDB,
 PARTITION p2014 VALUES LESS THAN (2014) ENGINE = InnoDB,
 PARTITION p2015 VALUES LESS THAN (2015) ENGINE = InnoDB,
 PARTITION p2016 VALUES LESS THAN (2016) ENGINE = InnoDB,
 PARTITION p2017 VALUES LESS THAN (2017) ENGINE = InnoDB,
 PARTITION p2018 VALUES LESS THAN (2018) ENGINE = InnoDB,
 PARTITION p2019 VALUES LESS THAN (2019) ENGINE = InnoDB,
 PARTITION p2020 VALUES LESS THAN (2020) ENGINE = InnoDB,
 PARTITION pmax VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */
1 row in set (0.00 sec)

root@localhost [test]> 

補足メモ:

パーティションでは無いですが、パスを変更してデータを配置する方法。
MYSQL DATA DIRECTORY と INDEX DIRECTORYの指定

5.7からは複数テーブルを配置出来る、GENERAL TABLESPACEが利用可能になります。
InnoDB General Tablespace


root@localhost [test]> CREATE TABLE `tbl_DATA_DIRECTORY` (
    ->   `member_id` varchar(40) NOT NULL,
    ->   `platform` varchar(10) NOT NULL,
    ->   `year` smallint(5) unsigned NOT NULL,
    ->   `month` tinyint(2) unsigned NOT NULL,
    ->   `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
    ->   PRIMARY KEY (`member_id`,`year`,`month`),
    ->   KEY `idx_tbl_DATA_DIRECTORY` (`year`),
    ->   KEY `idx_tbl_DATA_DIRECTORY_id` (`member_id`)
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DATA DIRECTORY = '/home/mysql/data';
Query OK, 0 rows affected (0.03 sec)

root@localhost [test]> 

■テーブル定義はDefault Dataディレクトリーで,データ用テーブルスペースが指定したディレクトリーに作成されます。


[root@GA01 test]# ls -l /usr/local/mysql/data/test/tbl_DATA*
-rw-rw----. 1 mysql mysql 8712  6月 30 15:05 /usr/local/mysql/data/test/tbl_DATA_DIRECTORY.frm
-rw-rw----. 1 mysql mysql   44  6月 30 15:05 /usr/local/mysql/data/test/tbl_DATA_DIRECTORY.isl
[root@GA01 test]# ls -l /home/mysql/data/test/
合計 192
-rw-rw----. 1 mysql mysql 131072  6月 30 15:05 tbl_DATA_DIRECTORY.ibd
[root@GA01 test]# 

基本ファイル構成


NoSQL with MySQL Cluster
本日、話をさせて頂いた、MySQL Clusterにおけるトランザクション対応NoSQLについての資料です。

MySQL ClusterはMySQLとは基本的には異なるデータベースです。
NDB(Network Database)に対して、MySQLからもNoSQLからもデータ処理出来るデータベースがMySQL Clusterです。
MySQLからはもともとストレージエンジンを選択出来るデータベースシステムですが、
MySQLはndbclusterというストレージエンジンとしてNDBを利用しています。

NDBはNDB API (C++)を経由してアクセスする事で,MySQLから独立して利用する事が可能です。
MySQLサーバの観点からは,NDB Clusterは行のテーブルを格納するためのストレージエンジンです。
NDB Clusterの観点からは、MySQLサーバインスタンスがクラスタに接続されているAPIのプロセスの一つです。

概要図
ndb_diag

Storage Engine
storage_engines

ndbinfo
データは、冗長化と拡張性の為にデータノード間で分散されています。
その状況は、ndbinfoを確認する事でも確認可能です。

ndbinfo

検証
先ずは、MySQL Clusterをダウンロードして頂き、MySQL Clsuterを設定して下さい。
設定が終了したら、MySQL ClusterにSQLで接続しスキーマとテスト用のテーブルを作成して下さい。
NDB APIからNoSQLでもNDBにコマンドでテーブルを作成出来ますが、その場合はMySQLからオブジェクトを見る事が出来ません。
MySQLとNoSQL両方から使いたい場合は、MySQLにて先ずはオブジェクト作成して下さい。

Download MySQL Cluster
https://dev.mysql.com/downloads/cluster/

18.2.2. Linux での MySQL Cluster のインストール
https://dev.mysql.com/doc/refman/5.6/ja/mysql-cluster-install-linux.html

5分で作るMySQL Cluster環境
http://www.ospn.jp/osc2013-kyoto/pdf/osc2013kyoto_mysql2.pdf


mysql> use TEST_DB
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show create table employee\G
*************************** 1. row ***************************
       Table: employee
Create Table: CREATE TABLE `employee` (
  `id` int(11) NOT NULL,
  `first` varchar(64) DEFAULT NULL,
  `last` varchar(64) DEFAULT NULL,
  `municipality` varchar(64) DEFAULT NULL,
  `started` varchar(64) DEFAULT NULL,
  `ended` varchar(64) DEFAULT NULL,
  `department` int(11) NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_u_hash` (`first`,`last`) USING HASH,
  KEY `idx_municipality` (`municipality`)
) ENGINE=ndbcluster DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

mysql> 

ClusterJ サンプルソース
MySQLClusterJ_Sample

MySQL Clusterへの接続文字列は適宜変更して下さい。
— com.mysql.clusterj.connectstring
— com.mysql.clusterj.database=TEST_DB

[SELL]

[root@Labs01 java]# cat clusterj.properties
# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

com.mysql.clusterj.connectstring=192.168.56.114:1186
com.mysql.clusterj.database=TEST_DB
com.mysql.clusterj.connect.retries=4
com.mysql.clusterj.connect.delay=5
com.mysql.clusterj.connect.verbose=1
com.mysql.clusterj.connect.timeout.before=30
com.mysql.clusterj.connect.timeout.after=20
com.mysql.clusterj.max.transactions=1024
[root@Labs01 java]#

[/SHELL]

コンパイル
※ javacにてコンパイル時には、clusterj-api-7.x.x.jarを含める必要があります。
※ パスは適宜書き換えて下さい。


javac -classpath /mysql-cluster-gpl-7.4.6/746bin/share/java/clusterj-api-7.4.6.jar:. Main.java Employee.java

実行例


java -classpath /mysql-cluster-gpl-7.4.6/746bin/share/java/clusterj-7.4.6.jar:. -Djava.library.path=/mysql-cluster-gpl-7.4.6/746bin/lib Main

上記の実行内容は、先にスキーマをSQLから作成してあるのでSQLでも見る事が出来ます。

del_in

それ以外の方法としては、NDB用にMySQL Clusterに用意されている以下のコマンドを利用すると良いでしょう。

ndb_show_tables

ndb_show_tables

ndb_select_all

ndb_select_all

SQLが得意な処理は、SQLで処理して、Primary Keyベースでの特定のデータに対しての処理などは、
MySQL ClusterでのNoSQLで処理するという方法も選択出来ます。
NDB APIはC++ですので、C++が得意な方はそのままC++で書いて高速な処理を検証してみるのも良いかと思います。
※ネットワークは重要です、トラフィックが多い場合は10Gなどの高速なネットワークをご利用下さい。