現状、まだLab版ですが、MySQL5.7の追加のプラグインとして、マルチマスタまたはアクティブ/アクティブレプリケーションをサポートする
同期レプリケーション型のグループレプリケーションが準備されています。まだ、Lab版という事もあり、機能追加やバグ対応などがまだまだ必要な段階ですが、LAB版→DR版→RC版→GA版と段々と安定してくると思いますので、次のLab版がリリースされたら是非検証環境で試してみて頂ければと思います。
マスターサーバーのHA対応やスレーブが多い環境で、マスターサーバーのレプリケーション負荷分散等に活用出来そうです。

Group Replication関連参考ブログを見て頂けると、基本的なインストール方法が書かれていますので試される場合は、此方を参考にして下さい。

http://mysqlhighavailability.com/getting-started-with-mysql-group-replication/

NODE1にてグループレプリケーション開始
※オプションファイルに書いておくことで、SETコマンドの実行は不要です。
※XCOMで通信する為のポートは、通常のMySQL PORT3306とは別にしてください。


root@localhost [mysql]> SET GLOBAL group_replication_group_name= "00000000-1111-2222-3333-123456789ABC";
Query OK, 0 rows affected (0.00 sec)

root@localhost [mysql]> SET GLOBAL group_replication_bootstrap_group= 1;
Query OK, 0 rows affected (0.00 sec)

root@localhost [mysql]> SET GLOBAL group_replication_local_address="192.168.56.101:13001";
Query OK, 0 rows affected (0.00 sec)

root@localhost [mysql]> SET GLOBAL group_replication_peer_addresses= "192.168.56.101:13001,192.168.56.102:13001";
Query OK, 0 rows affected (0.00 sec)

root@localhost [mysql]> SET GLOBAL group_replication_recovery_user='rpl_user';
Query OK, 0 rows affected (0.00 sec)

root@localhost [mysql]> SET GLOBAL group_replication_recovery_password='rpl_pass';
Query OK, 0 rows affected (0.00 sec)

root@localhost [mysql]> START GROUP_REPLICATION;
Query OK, 0 rows affected (2.59 sec)

root@localhost [mysql]> SET GLOBAL group_replication_bootstrap_group= 0;
Query OK, 0 rows affected (0.00 sec)

root@localhost [mysql]> SELECT * FROM performance_schema.replication_connection_status\G
*************************** 1. row ***************************
             CHANNEL_NAME: group_replication_applier
               GROUP_NAME: 00000000-1111-2222-3333-123456789ABC
              SOURCE_UUID: 00000000-1111-2222-3333-123456789ABC
                THREAD_ID: NULL
            SERVICE_STATE: ON
COUNT_RECEIVED_HEARTBEATS: 0
 LAST_HEARTBEAT_TIMESTAMP: 0000-00-00 00:00:00
 RECEIVED_TRANSACTION_SET: 00000000-1111-2222-3333-123456789abc:1-4
        LAST_ERROR_NUMBER: 0
       LAST_ERROR_MESSAGE: 
     LAST_ERROR_TIMESTAMP: 0000-00-00 00:00:00
1 row in set (0.00 sec)

root@localhost [mysql]> 


NODE2をGRに参加してみます。


root@localhost [mysql]> SET GLOBAL group_replication_group_name= "00000000-1111-2222-3333-123456789ABC";
Query OK, 0 rows affected (0.00 sec)

root@localhost [mysql]> SET GLOBAL group_replication_local_address="192.168.56.102:13001";
Query OK, 0 rows affected (0.00 sec)

root@localhost [mysql]> SET GLOBAL group_replication_peer_addresses= "192.168.56.101:13001,192.168.56.102:13001";
Query OK, 0 rows affected (0.00 sec)

root@localhost [mysql]> SET GLOBAL group_replication_recovery_user='rpl_user';
Query OK, 0 rows affected (0.00 sec)

root@localhost [mysql]> SET GLOBAL group_replication_recovery_password='rpl_pass';
Query OK, 0 rows affected (0.00 sec)

root@localhost [mysql]> START GROUP_REPLICATION;
Query OK, 0 rows affected (3.04 sec)

root@localhost [mysql]> SELECT * FROM performance_schema.replication_group_members\G
*************************** 1. row ***************************
CHANNEL_NAME: group_replication_applier
   MEMBER_ID: 29ea17bc-3848-11e6-9900-0800279ca844
 MEMBER_HOST: misc01
 MEMBER_PORT: 3306
MEMBER_STATE: ONLINE
*************************** 2. row ***************************
CHANNEL_NAME: group_replication_applier
   MEMBER_ID: 5b07d5d8-4057-11e6-a315-0800279cea3c
 MEMBER_HOST: misc02
 MEMBER_PORT: 3306
MEMBER_STATE: ONLINE
2 rows in set (0.01 sec)

root@localhost [mysql]> SELECT * FROM performance_schema.replication_connection_status\G
*************************** 1. row ***************************
             CHANNEL_NAME: group_replication_applier
               GROUP_NAME: 00000000-1111-2222-3333-123456789ABC
              SOURCE_UUID: 00000000-1111-2222-3333-123456789ABC
                THREAD_ID: NULL
            SERVICE_STATE: ON
COUNT_RECEIVED_HEARTBEATS: 0
 LAST_HEARTBEAT_TIMESTAMP: 0000-00-00 00:00:00
 RECEIVED_TRANSACTION_SET: 00000000-1111-2222-3333-123456789abc:4
        LAST_ERROR_NUMBER: 0
       LAST_ERROR_MESSAGE: 
     LAST_ERROR_TIMESTAMP: 0000-00-00 00:00:00
1 row in set (0.00 sec)

root@localhost [mysql]> 



group_members

MEMBER_STATEが共にONLINEになっているので、DDL、DMLを処理して同期されているか確認して見ます
先ずは、NODE1でデータベース、テーブルを作成してからデータを1件入れてみます。
NODE1で作成したオブジェクトやデータはNODE2でも確認出来ます。
また、同様にNODE2で入れたデータは、NODE1で確認する事が出来ます。


root@localhost [mysql]> CREATE DATABASE GR_TEST;
Query OK, 1 row affected (0.03 sec)

root@localhost [mysql]> use GR_TEST;
Database changed
root@localhost [GR_TEST]> CREATE TABLE GR_TEST.T01 (
    -> ID INT NOT NULL PRIMARY KEY,
    -> MEMO varchar(30) COLLATE utf8_bin NOT NULL DEFAULT ''
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Query OK, 0 rows affected (0.07 sec)

root@localhost [GR_TEST]> INSERT INTO GR_TEST.T01(ID,MEMO) VALUES (1,@@hostname);
Query OK, 1 row affected (0.07 sec)

root@localhost [GR_TEST]> select * from T01;
+----+--------+
| ID | MEMO   |
+----+--------+
|  1 | misc01 |
+----+--------+
1 row in set (0.01 sec)

root@localhost [GR_TEST]> 

NODE2でデータを確認してみます。


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

root@localhost [mysql]> use GR_TEST
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
root@localhost [GR_TEST]> select * from T01;
+----+--------+
| ID | MEMO   |
+----+--------+
|  1 | misc01 |
+----+--------+
1 row in set (0.00 sec)

root@localhost [GR_TEST]> INSERT INTO GR_TEST.T01(ID,MEMO) VALUES (2,@@hostname);
Query OK, 1 row affected (0.04 sec)

root@localhost [GR_TEST]> select * from T01;
+----+--------+
| ID | MEMO   |
+----+--------+
|  1 | misc01 |
|  2 | misc02 |
+----+--------+
2 rows in set (0.00 sec)

root@localhost [GR_TEST]> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | 29ea17bc-3848-11e6-9900-0800279ca844 | misc01      |        3306 | ONLINE       |
| group_replication_applier | 5b07d5d8-4057-11e6-a315-0800279cea3c | misc02      |        3306 | ONLINE       |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
2 rows in set (0.00 sec)

root@localhost [GR_TEST]> SELECT * FROM performance_schema.replication_connection_status\G
*************************** 1. row ***************************
             CHANNEL_NAME: group_replication_applier
               GROUP_NAME: 00000000-1111-2222-3333-123456789ABC
              SOURCE_UUID: 00000000-1111-2222-3333-123456789ABC
                THREAD_ID: NULL
            SERVICE_STATE: ON
COUNT_RECEIVED_HEARTBEATS: 0
 LAST_HEARTBEAT_TIMESTAMP: 0000-00-00 00:00:00
 RECEIVED_TRANSACTION_SET: 00000000-1111-2222-3333-123456789abc:4-7
        LAST_ERROR_NUMBER: 0
       LAST_ERROR_MESSAGE: 
     LAST_ERROR_TIMESTAMP: 0000-00-00 00:00:00
1 row in set (0.00 sec)

root@localhost [GR_TEST]> 

NODE2で入れたデータはNODE1でも確認出来ました。
これで、双方向にレプリケーションが張られている事が確認出来ました。


root@localhost [GR_TEST]> select * from T01;
+----+--------+
| ID | MEMO   |
+----+--------+
|  1 | misc01 |
|  2 | misc02 |
+----+--------+
2 rows in set (0.00 sec)


root@localhost [GR_TEST]> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | 29ea17bc-3848-11e6-9900-0800279ca844 | misc01      |        3306 | ONLINE       |
| group_replication_applier | 5b07d5d8-4057-11e6-a315-0800279cea3c | misc02      |        3306 | ONLINE       |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
2 rows in set (0.00 sec)

root@localhost [GR_TEST]> SELECT * FROM performance_schema.replication_connection_status\G
*************************** 1. row ***************************
             CHANNEL_NAME: group_replication_applier
               GROUP_NAME: 00000000-1111-2222-3333-123456789ABC
              SOURCE_UUID: 00000000-1111-2222-3333-123456789ABC
                THREAD_ID: NULL
            SERVICE_STATE: ON
COUNT_RECEIVED_HEARTBEATS: 0
 LAST_HEARTBEAT_TIMESTAMP: 0000-00-00 00:00:00
 RECEIVED_TRANSACTION_SET: 00000000-1111-2222-3333-123456789abc:4-7
        LAST_ERROR_NUMBER: 0
       LAST_ERROR_MESSAGE: 
     LAST_ERROR_TIMESTAMP: 0000-00-00 00:00:00
1 row in set (0.00 sec)

root@localhost [GR_TEST]> 

GTIDの状態を確認
自分で更新したデータに関しては、RECEIVED_TRANSACTION_SETには反映されないので、@@GLOBAL.GTID_EXECUTEDで何処まで適用されているか確認。


root@localhost [GR_TEST]> SELECT * FROM performance_schema.replication_connection_status\G
*************************** 1. row ***************************
             CHANNEL_NAME: group_replication_applier
               GROUP_NAME: 00000000-1111-2222-3333-123456789ABC
              SOURCE_UUID: 00000000-1111-2222-3333-123456789ABC
                THREAD_ID: NULL
            SERVICE_STATE: ON
COUNT_RECEIVED_HEARTBEATS: 0
 LAST_HEARTBEAT_TIMESTAMP: 0000-00-00 00:00:00
 RECEIVED_TRANSACTION_SET: 00000000-1111-2222-3333-123456789abc:4-7:9
        LAST_ERROR_NUMBER: 0
       LAST_ERROR_MESSAGE: 
     LAST_ERROR_TIMESTAMP: 0000-00-00 00:00:00
1 row in set (0.00 sec)

root@localhost [GR_TEST]> SELECT @@GLOBAL.GTID_EXECUTED;
+-------------------------------------------+
| @@GLOBAL.GTID_EXECUTED                    |
+-------------------------------------------+
| 00000000-1111-2222-3333-123456789abc:1-10 |
+-------------------------------------------+
1 row in set (0.00 sec)

root@localhost [GR_TEST]> 

NODE1とNODE2の間で、トランザクションの競合が発生した場合
(同時に同じデータを更新しようとした場合)

NODE1で先ずは、トランザクションを張って処理を実行してみます。そして、Commitを行う前に、NODE2で同じデータを更新処理してみます。
最初に処理を開始した、NODE1は問題無く処理出来てますが、NODE2のCommit処理はエラーで終了しています。

root@localhost [GR_TEST]> select * from T01;
+----+--------+
| ID | MEMO   |
+----+--------+
|  1 | misc01 |
|  2 | misc02 |
|  3 | misc01 |
|  4 | misc02 |
+----+--------+
4 rows in set (0.00 sec)

root@localhost [GR_TEST]> start transaction;update T01 set MEMO = @@hostname where ID = 4;
Query OK, 0 rows affected (0.00 sec)

Query OK, 1 row affected (0.03 sec)
Rows matched: 1  Changed: 1  Warnings: 0

root@localhost [GR_TEST]> commit;
Query OK, 0 rows affected (0.01 sec)

root@localhost [GR_TEST]> select * from T01;
+----+--------+
| ID | MEMO   |
+----+--------+
|  1 | misc01 |
|  2 | misc02 |
|  3 | misc01 |
|  4 | misc01 |
+----+--------+
4 rows in set (0.00 sec)

root@localhost [GR_TEST]> 

NODE2は、ERROR 1180 (HY000): Got error 149 during COMMITでエラーになっています。

root@localhost [GR_TEST]> select * from T01;
+----+--------+
| ID | MEMO   |
+----+--------+
|  1 | misc01 |
|  2 | misc02 |
|  3 | misc01 |
|  4 | misc02 |
+----+--------+
4 rows in set (0.00 sec)

root@localhost [GR_TEST]> start transaction;update T01 set MEMO = 'MISC02' where ID = 4;
Query OK, 0 rows affected (0.00 sec)

Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

root@localhost [GR_TEST]> commit;
ERROR 1180 (HY000): Got error 149 during COMMIT
root@localhost [GR_TEST]> select * from T01;
+----+--------+
| ID | MEMO   |
+----+--------+
|  1 | misc01 |
|  2 | misc02 |
|  3 | misc01 |
|  4 | misc01 |
+----+--------+
4 rows in set (0.00 sec)

root@localhost [GR_TEST]> 

group_replication_tran_conf

ONLINE DDLでALTERを実行した場合
結果としては、問題無くDDLも実行可能で伝搬されます。但し、現状のGRの仕様としては、オンラインスキーマ変更は推奨されていないので、
1)BINLOGをOFFにしてDDL実行 2) 他のノードも同様にBINLOGをOFFにしてDDL実行 3) 最後にアプリケーションを変更し変更を反映させるのが良さそうです。

NODE1にてDDLを実行して列を追加してみます。

root@localhost [GR_TEST]> ALTER TABLE T01 add column created_time datetime DEFAULT CURRENT_TIMESTAMP;
Query OK, 0 rows affected (0.12 sec)
Records: 0  Duplicates: 0  Warnings: 0

root@localhost [GR_TEST]> desc T01;
+--------------+-------------+------+-----+-------------------+-------+
| Field        | Type        | Null | Key | Default           | Extra |
+--------------+-------------+------+-----+-------------------+-------+
| ID           | int(11)     | NO   | PRI | NULL              |       |
| MEMO         | varchar(30) | NO   |     |                   |       |
| created_time | datetime    | YES  |     | CURRENT_TIMESTAMP |       |
+--------------+-------------+------+-----+-------------------+-------+
3 rows in set (0.03 sec)

root@localhost [GR_TEST]> select * from T01;
+----+--------+---------------------+
| ID | MEMO   | created_time        |
+----+--------+---------------------+
|  1 | misc01 | 2016-07-17 15:40:29 |
|  2 | misc02 | 2016-07-17 15:40:29 |
|  3 | misc01 | 2016-07-17 15:40:29 |
|  4 | misc02 | 2016-07-17 15:40:29 |
+----+--------+---------------------+
4 rows in set (0.00 sec)

root@localhost [GR_TEST]> INSERT INTO GR_TEST.T01(ID,MEMO) VALUES (5,@@hostname);
Query OK, 1 row affected (0.01 sec)

root@localhost [GR_TEST]> select * from T01;
+----+--------+---------------------+
| ID | MEMO   | created_time        |
+----+--------+---------------------+
|  1 | misc01 | 2016-07-17 15:40:29 |
|  2 | misc02 | 2016-07-17 15:40:29 |
|  3 | misc01 | 2016-07-17 15:40:29 |
|  4 | misc02 | 2016-07-17 15:40:29 |
|  5 | misc01 | 2016-07-17 15:42:33 |
+----+--------+---------------------+
5 rows in set (0.00 sec)

root@localhost [GR_TEST]> 

NODE2でNODE1で実行されたDDLの結果を確認して、NODE2からデータを追加してみます。

root@localhost [GR_TEST]> desc T01;
+--------------+-------------+------+-----+-------------------+-------+
| Field        | Type        | Null | Key | Default           | Extra |
+--------------+-------------+------+-----+-------------------+-------+
| ID           | int(11)     | NO   | PRI | NULL              |       |
| MEMO         | varchar(30) | NO   |     |                   |       |
| created_time | datetime    | YES  |     | CURRENT_TIMESTAMP |       |
+--------------+-------------+------+-----+-------------------+-------+
3 rows in set (0.01 sec)

root@localhost [GR_TEST]> select * from T01;
+----+--------+---------------------+
| ID | MEMO   | created_time        |
+----+--------+---------------------+
|  1 | misc01 | 2016-07-17 15:40:29 |
|  2 | misc02 | 2016-07-17 15:40:29 |
|  3 | misc01 | 2016-07-17 15:40:29 |
|  4 | misc02 | 2016-07-17 15:40:29 |
|  5 | misc01 | 2016-07-17 15:42:33 |
+----+--------+---------------------+
5 rows in set (0.00 sec)

root@localhost [GR_TEST]> INSERT INTO GR_TEST.T01(ID,MEMO) VALUES (6,@@hostname);
Query OK, 1 row affected (0.01 sec)

root@localhost [GR_TEST]> select * from T01;
+----+--------+---------------------+
| ID | MEMO   | created_time        |
+----+--------+---------------------+
|  1 | misc01 | 2016-07-17 15:40:29 |
|  2 | misc02 | 2016-07-17 15:40:29 |
|  3 | misc01 | 2016-07-17 15:40:29 |
|  4 | misc02 | 2016-07-17 15:40:29 |
|  5 | misc01 | 2016-07-17 15:42:33 |
|  6 | misc02 | 2016-07-17 15:44:03 |
+----+--------+---------------------+
6 rows in set (0.00 sec)


root@localhost [GR_TEST]> SELECT @@GLOBAL.GTID_EXECUTED;
+-------------------------------------------+
| @@GLOBAL.GTID_EXECUTED                    |
+-------------------------------------------+
| 00000000-1111-2222-3333-123456789abc:1-15 |
+-------------------------------------------+
1 row in set (0.00 sec)

root@localhost [GR_TEST]> SELECT * FROM performance_schema.replication_connection_status\G
*************************** 1. row ***************************
             CHANNEL_NAME: group_replication_applier
               GROUP_NAME: 00000000-1111-2222-3333-123456789ABC
              SOURCE_UUID: 00000000-1111-2222-3333-123456789ABC
                THREAD_ID: NULL
            SERVICE_STATE: ON
COUNT_RECEIVED_HEARTBEATS: 0
 LAST_HEARTBEAT_TIMESTAMP: 0000-00-00 00:00:00
 RECEIVED_TRANSACTION_SET: 00000000-1111-2222-3333-123456789abc:4-7:9:11:13-14
        LAST_ERROR_NUMBER: 0
       LAST_ERROR_MESSAGE: 
     LAST_ERROR_TIMESTAMP: 0000-00-00 00:00:00
1 row in set (0.00 sec)

root@localhost [GR_TEST]> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | 29ea17bc-3848-11e6-9900-0800279ca844 | misc01      |        3306 | ONLINE       |
| group_replication_applier | 5b07d5d8-4057-11e6-a315-0800279cea3c | misc02      |        3306 | ONLINE       |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
2 rows in set (0.00 sec)

root@localhost [GR_TEST]> 

NODE2でデータを入れたあとにNODE1の状況を確認してみます。
特に問題無く、データが反映されている事が確認出来ます。
レプリケーションもRAWベースなので特に時間関連の関数なども気にしなくて良いです。


root@localhost [GR_TEST]> select * from T01;
+----+--------+---------------------+
| ID | MEMO   | created_time        |
+----+--------+---------------------+
|  1 | misc01 | 2016-07-17 15:40:29 |
|  2 | misc02 | 2016-07-17 15:40:29 |
|  3 | misc01 | 2016-07-17 15:40:29 |
|  4 | misc02 | 2016-07-17 15:40:29 |
|  5 | misc01 | 2016-07-17 15:42:33 |
|  6 | misc02 | 2016-07-17 15:44:03 |
+----+--------+---------------------+
6 rows in set (0.01 sec)

root@localhost [GR_TEST]> SELECT @@GLOBAL.GTID_EXECUTED;
+-------------------------------------------+
| @@GLOBAL.GTID_EXECUTED                    |
+-------------------------------------------+
| 00000000-1111-2222-3333-123456789abc:1-15 |
+-------------------------------------------+
1 row in set (0.00 sec)

root@localhost [GR_TEST]> SELECT * FROM performance_schema.replication_connection_status\G
*************************** 1. row ***************************
             CHANNEL_NAME: group_replication_applier
               GROUP_NAME: 00000000-1111-2222-3333-123456789ABC
              SOURCE_UUID: 00000000-1111-2222-3333-123456789ABC
                THREAD_ID: NULL
            SERVICE_STATE: ON
COUNT_RECEIVED_HEARTBEATS: 0
 LAST_HEARTBEAT_TIMESTAMP: 0000-00-00 00:00:00
 RECEIVED_TRANSACTION_SET: 00000000-1111-2222-3333-123456789abc:1-4:8:10:12:15
        LAST_ERROR_NUMBER: 0
       LAST_ERROR_MESSAGE: 
     LAST_ERROR_TIMESTAMP: 0000-00-00 00:00:00
1 row in set (0.00 sec)

root@localhost [GR_TEST]> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | 29ea17bc-3848-11e6-9900-0800279ca844 | misc01      |        3306 | ONLINE       |
| group_replication_applier | 5b07d5d8-4057-11e6-a315-0800279cea3c | misc02      |        3306 | ONLINE       |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
2 rows in set (0.00 sec)

root@localhost [GR_TEST]> 

余談: Group Replicationは全てマスターなので、Show Slave Statusは不要ですね。


/*** NODE1 ***/
root@localhost [GR_TEST]> show slave status\G
Empty set (0.00 sec)

root@localhost [GR_TEST]> show master status;
+------------------+----------+--------------+------------------+-------------------------------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                         |
+------------------+----------+--------------+------------------+-------------------------------------------+
| mysql-bin.000001 |     4391 |              |                  | 00000000-1111-2222-3333-123456789abc:1-15 |
+------------------+----------+--------------+------------------+-------------------------------------------+
1 row in set (0.00 sec)

root@localhost [GR_TEST]> 


/*** NODE2 ***/
root@localhost [GR_TEST]> show slave status\G
Empty set (0.02 sec)

root@localhost [GR_TEST]> show master status;
+------------------+----------+--------------+------------------+-------------------------------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                         |
+------------------+----------+--------------+------------------+-------------------------------------------+
| mysql-bin.000001 |     4391 |              |                  | 00000000-1111-2222-3333-123456789abc:1-15 |
+------------------+----------+--------------+------------------+-------------------------------------------+
1 row in set (0.00 sec)

root@localhost [GR_TEST]> 

参考パラメータ


root@localhost [GR_TEST]> show global variables like '%group_repli%';
+---------------------------------------------------+-------------------------------------------+
| Variable_name                                     | Value                                     |
+---------------------------------------------------+-------------------------------------------+
| group_replication_allow_local_lower_version_join  | OFF                                       |
| group_replication_auto_increment_increment        | 7                                         |
| group_replication_bootstrap_group                 | OFF                                       |
| group_replication_components_stop_timeout         | 31536000                                  |
| group_replication_gcs_engine                      | xcom                                      |
| group_replication_group_name                      | 00000000-1111-2222-3333-123456789ABC      |
| group_replication_local_address                   | 192.168.56.101:13001                      |
| group_replication_peer_addresses                  | 192.168.56.101:13001,192.168.56.102:13001 |
| group_replication_pipeline_type_var               | STANDARD                                  |
| group_replication_recovery_complete_at            | TRANSACTIONS_CERTIFIED                    |
| group_replication_recovery_password               |                                           |
| group_replication_recovery_reconnect_interval     | 120                                       |
| group_replication_recovery_retry_count            | 2                                         |
| group_replication_recovery_ssl_ca                 |                                           |
| group_replication_recovery_ssl_capath             |                                           |
| group_replication_recovery_ssl_cert               |                                           |
| group_replication_recovery_ssl_cipher             |                                           |
| group_replication_recovery_ssl_crl                |                                           |
| group_replication_recovery_ssl_crlpath            |                                           |
| group_replication_recovery_ssl_key                |                                           |
| group_replication_recovery_ssl_verify_server_cert | OFF                                       |
| group_replication_recovery_use_ssl                | OFF                                       |
| group_replication_recovery_user                   | rpl_user                                  |
| group_replication_start_on_boot                   | OFF                                       |
+---------------------------------------------------+-------------------------------------------+
24 rows in set (0.01 sec)

root@localhost [GR_TEST]> 

【参考】

LABサイト
http://labs.mysql.com/

Group Replication関連参考ブログ
http://mysqlhighavailability.com/getting-started-with-mysql-group-replication/

MySQLセミナー資料
http://downloads.mysql.com/presentations/20160510_06_MySQL_57_ReplicationEnhancements.pdf

Auto Incrementの値
http://mysqlhighavailability.com/mysql-group-replication-auto-increment-configuration-handling/


MySQL5.7.13以降における、Enterprise Audit機能の改善

MySQL5.7.13以降で、全てのユーザー若しくは、特定ユーザーが特定のテーブルに対して行った、read,insert,update,delete処理のみを監査出来るようになりました。
フィルター作成はJSONフォーマットで定義するようです。この機能は、以前から待ち望んでいたので、嬉しい機能の一つです。

【検証バージョン】5.7.13-enterprise-commercial-advanced-log

フィルタリング詳細:
https://dev.mysql.com/doc/refman/5.7/en/audit-log-filtering.html

例) こちらは、confidentialテーブルに対してselectしたSQLだけ監査するようにフィルターしてある場合の監査ログです。
【フィルター】

root@localhost [mysql]> select * from audit_log_filter;
+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
| NAME             | FILTER                                                                                                                                            |
+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
| log_all          | {"filter": {"log": true}}                                                                                                                         |
| log_confidential | {"filter": {"class": {"name": "table_access", "event": {"log": {"field": {"name": "table_name.str", "value": "confidential"}}, "name": "read"}}}} |
+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------+

【監査ログ】
audit

1) 以下のように書かれていたので、既にインストール済みバージョンをアンインストールしました。
If the audit_log plugin is already installed from a version of MySQL before 5.7.13,
uninstall it using this statement and then restart the server before installing the current version:

■ オプションファイルもコメントアウト


[mysqld]
#plugin-load=audit_log.so
#audit-log=FORCE_PLUS_PERMANENT

■ Uninstall作業

root@localhost [(none)]> UNINSTALL PLUGIN audit_log;
Query OK, 0 rows affected, 1 warning (0.00 sec)

root@localhost [(none)]> show warnings;
+---------+------+----------------------------------------------------+
| Level   | Code | Message                                            |
+---------+------+----------------------------------------------------+
| Warning | 1620 | Plugin is busy and will be uninstalled on shutdown |
+---------+------+----------------------------------------------------+
1 row in set (0.00 sec)

root@localhost [(none)]> exit
Bye


[root@misc02 admin]# /etc/init.d/mysql.server restart

■ ロードされていない事を確認してインストール準備完了

root@localhost [information_Schema]> select PLUGIN_NAME,PLUGIN_STATUS,PLUGIN_TYPE,LOAD_OPTION from FROM INFORMATION_SCHEMA.PLUGINS where PLUGIN_NAME like 'audit%';
Empty set (0.00 sec)

root@localhost [information_Schema]> 

■ログ
参考) 5.7.13のログを確認したら、UNINSTALL前は以下のようなログが出ていました。

[root@misc01 admin]# cat /usr/local/mysql/data/error.log | grep audit
2016-06-15T21:26:01.568228+09:00 0 [Warning] Plugin audit_log reported: 'Audit Log plugin supports a filtering, which has not been installed yet. Audit Log plugin will run in the legacy mode, which will be disabled in the next release.'
2016-06-15T21:34:11.395386+09:00 4 [Note] Shutting down plugin 'audit_log'
[root@misc01 admin]# 

2)スクリプトを利用してインストールします。(これまで、Audit Pluginを利用した事が無ければここから設定開始)

スクリプトの内容を確認すると2つのテーブルと5つのファンクション,そして、AUDIT PLUGINのインストールを行っています。テーブルはInnoDBに進もうとしているのに、なぜかMyISAMを利用していますが。。。あとユーザーのサイズ制限がなぜかVARCHAAR(16)
こちらは、後で問い合わせしてみたいと思います。
———————————————————————————-
audit_log_filter_linux_install.sqlの内容
———————————————————————————-


USE mysql;

CREATE TABLE IF NOT EXISTS audit_log_filter(NAME VARCHAR(64) BINARY NOT NULL PRIMARY KEY, FILTER JSON NOT NULL) engine= MyISAM;
CREATE TABLE IF NOT EXISTS audit_log_user(USER VARCHAR(16) BINARY NOT NULL, HOST VARCHAR(60) BINARY NOT NULL, FILTERNAME VARCHAR(64) BINARY NOT NULL, PRIMARY KEY (USER, HOST), FOREIGN KEY (FILTERNAME) REFERENCES mysql.audit_log_filter(NAME)) engine= MyISAM;

INSTALL PLUGIN audit_log SONAME 'audit_log.so';

CREATE FUNCTION audit_log_filter_set_filter RETURNS STRING SONAME 'audit_log.so';
CREATE FUNCTION audit_log_filter_remove_filter RETURNS STRING SONAME 'audit_log.so';
CREATE FUNCTION audit_log_filter_set_user RETURNS STRING SONAME 'audit_log.so';
CREATE FUNCTION audit_log_filter_remove_user RETURNS STRING SONAME 'audit_log.so';
CREATE FUNCTION audit_log_filter_flush RETURNS STRING SONAME 'audit_log.so';

SELECT audit_log_filter_flush() AS 'Result';

Installの実行
インストールスクリプトはSHAREフォルダーにあります。(WindowsとLinuxで別々なので注意して下さい)


[root@misc01 admin]# mysql -u root -p < /usr/local/mysql/share/audit_log_filter_linux_install.sql 
Enter password: 
Result
OK
[root@misc01 admin]# 


[root@misc01 admin]# mysql -u root -p -e "select PLUGIN_NAME,PLUGIN_STATUS,PLUGIN_TYPE,LOAD_OPTION FROM INFORMATION_SCHEMA.PLUGINS where PLUGIN_NAME like 'audit%'"
Enter password: 
+-------------+---------------+-------------+-------------+
| PLUGIN_NAME | PLUGIN_STATUS | PLUGIN_TYPE | LOAD_OPTION |
+-------------+---------------+-------------+-------------+
| audit_log   | ACTIVE        | AUDIT       | ON          |
+-------------+---------------+-------------+-------------+
[root@misc01 admin]# 




root@localhost [mysql]> show tables from mysql like 'audit%';
+--------------------------+
| Tables_in_mysql (audit%) |
+--------------------------+
| audit_log_filter         |
| audit_log_user           |
+--------------------------+
2 rows in set (0.00 sec)

root@localhost [mysql]> 

ここで、監査の初期設定は完了です。
これから、フィルター設定を幾つか入れて確認してみます。

3) 監査用のユーザー作成、ルール作成、ルール適用して検証してみます


root@localhost [mysql]> CREATE USER 'audit_target';
Query OK, 0 rows affected (0.00 sec)

root@localhost [mysql]> GRANT ALL ON *.* TO 'audit_target';
Query OK, 0 rows affected (0.00 sec)

root@localhost [mysql]> SELECT user, host FROM mysql.user WHERE user = 'audit_target';
+----------------+------+
| user           | host |
+----------------+------+
| audit_target   | %    |
+----------------+------+
1 row in set (0.00 sec)

root@localhost [mysql]> select * from audit_log_user;
Empty set (0.00 sec)

root@localhost [mysql]> select * from audit_log_filter;
Empty set (0.00 sec)

root@localhost [mysql]> SELECT audit_log_filter_set_filter('log_all', '{ "filter": { "log": true } }') AS 'Result';
+--------+
| Result |
+--------+
| OK     |
+--------+
1 row in set (0.00 sec)

root@localhost [mysql]> select * from audit_log_filter;
+-------------+---------------------------+
| NAME        | FILTER                    |
+-------------+---------------------------+
| log_all     | {"filter": {"log": true}} |
+-------------+---------------------------+
1 row in set (0.00 sec)

root@localhost [mysql]> SELECT audit_log_filter_set_user('audit_target@%', 'log_all') AS 'Result';
+--------+
| Result |
+--------+
| OK     |
+--------+
1 row in set (0.00 sec)

root@localhost [mysql]> select * from audit_log_user;
+----------------+------+-------------+
| USER           | HOST | FILTERNAME  |
+----------------+------+-------------+
| audit_target   | %    | log_all     |
+----------------+------+-------------+
1 row in set (0.00 sec)

root@localhost [mysql]> 

4) 別ホストから対象アカウントを利用してアクセスしてみます。


[root@misc02 admin]# mysql -h 192.168.56.113 -u audit_target
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 5.7.13-enterprise-commercial-advanced-log MySQL Enterprise Server - Advanced Edition (Commercial)

Copyright (c) 2000, 2016, 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.

audit_target@192.168.56.113 [(none)]> CREATE DATABASE audit_log_test_db;
Query OK, 1 row affected (0.05 sec)

audit_target@192.168.56.113 [(none)]> USE audit_log_test_db;
Database changed

audit_target@192.168.56.113 [audit_log_test_db]> CREATE TABLE confidential (memo varchar(100));
Query OK, 0 rows affected (0.02 sec)

audit_target@192.168.56.113 [audit_log_test_db]> INSERT INTO audit_log_test_table VALUES(1);
Query OK, 1 row affected (0.02 sec)

audit_target@192.168.56.113 [audit_log_test_db]> exit
Bye
[root@misc02 admin]# 

■上記のログがAuditログに記録されませんでした。
検証したところ、USER()を見ているようでした。

注意

current_user()を認識していないのは、Bugとの回答を頂きました。
既に修正済みで、次のメンテナンスリリースでFIXされるとの事でした。
なので、MySQL5.7.14を待ちたいと思います。

FIX後は以下の様に’%’でホストを指定している場合、user()毎に作成する必要は有りません。

また、JSONで定義を作成し有効にした場合に、mysqlクライアントからの接続出来ますが、
workbenchから接続出来なくなる不具合があるようです。Bug Reportを上げたので、5.7.13で利用される場合は制限がある事をご理解下さい。
http://bugs.mysql.com/bug.php?id=81897

上記修正されました。
Audit log filtering against the user was performing comparisons against USER(), not CURRENT_USER(). (Bug #23344762)
https://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-14.html


audit_target@192.168.56.113 [(none)]> select user(),current_user();
+-----------------------+------------------+
| user()                | current_user()   |
+-----------------------+------------------+
| audit_target@misc02   | audit_target@%   |
+-----------------------+------------------+
1 row in set (0.00 sec)

以下のように対象HOSTを追加しました。
追加したところ、audit_targetのAuditログが記録されている事が確認出来ました。

(例)
SELECT audit_log_filter_set_user(‘audit_target@misc02’, ‘log_all’) AS ‘Result’;


root@localhost [mysql]> select * from audit_log_user;select * from audit_log_filter;
+--------------+----------------+------------+
| USER         | HOST           | FILTERNAME |
+--------------+----------------+------------+
| audit_target | localhost      | log_all    |
| audit_target | %              | log_all    |
| audit_target | 192.168.56.109 | log_all    |
| audit_target | misc02         | log_all    |
+--------------+----------------+------------+
4 rows in set (0.00 sec)

root@localhost [mysql]> 

5) 基本的な機能は確認出来たので、ユーザー、テーブル、DMLの種類によるフィルタリングを確認してみます。
※ 全ての処理はもちろん取得し記録出来るので、特定のオブジェクトに対しての特定の処理のみを確認しています。

ここではユーザーを作成して、confidentialテーブルへのREAD(select)のみをログに記録する設定をしています。
READのみなので、INSERTはここでは取得していません。


root@localhost [mysql]> select * from audit_log_user;select * from audit_log_filter;
+--------------+----------------+------------+
| USER         | HOST           | FILTERNAME |
+--------------+----------------+------------+
| audit_target | localhost      | log_all    |
| audit_target | %              | log_all    |
| audit_target | 192.168.56.109 | log_all    |
| audit_target | misc02         | log_all    |
+--------------+----------------+------------+
4 rows in set (0.00 sec)

root@localhost [mysql]> SELECT audit_log_filter_set_filter('log_confidential', '{ "filter": { "class": { "name": "table_access","event": { "name": "read","log": { "field": { "name": "table_name.str","value": "confidential" } } } } } }');
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| audit_log_filter_set_filter('log_confidential', '{ "filter": { "class": { "name": "table_access","event": { "name": "read","log": { "field": { "name": "table_name.str","value": "confidential" } } } } } }') |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| OK                                                                                                                                                                                                              |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)

audit_target@localhost [mysql]> 


root@localhost [mysql]> CREATE USER confidential@'%';
Query OK, 0 rows affected (0.00 sec)

root@localhost [mysql]> alter user confidential@'%' identified by 'password';
Query OK, 0 rows affected (0.00 sec)

root@localhost [mysql]> GRANT ALL ON *.* TO 'confidential'@'%';
Query OK, 0 rows affected (0.00 sec)

root@localhost [mysql]> SELECT audit_log_filter_set_user('confidential@%','log_confidential');
+----------------------------------------------------------------+
| audit_log_filter_set_user('confidential@%','log_confidential') |
+----------------------------------------------------------------+
| OK                                                             |
+----------------------------------------------------------------+
1 row in set (0.00 sec)

root@localhost [mysql]> SELECT audit_log_filter_set_user('confidential@localhost','log_confidential');
+------------------------------------------------------------------------+
| audit_log_filter_set_user('confidential@localhost','log_confidential') |
+------------------------------------------------------------------------+
| OK                                                                     |
+------------------------------------------------------------------------+
1 row in set (0.00 sec)

root@localhost [mysql]>  SELECT audit_log_filter_set_user('confidential@192.168.56.109','log_confidential');
+-----------------------------------------------------------------------------+
| audit_log_filter_set_user('confidential@192.168.56.109','log_confidential') |
+-----------------------------------------------------------------------------+
| OK                                                                          |
+-----------------------------------------------------------------------------+
1 row in set (0.00 sec)

root@localhost [mysql]> SELECT audit_log_filter_set_user('confidential@misc02','log_confidential');
+---------------------------------------------------------------------+
| audit_log_filter_set_user('confidential@misc02','log_confidential') |
+---------------------------------------------------------------------+
| OK                                                                  |
+---------------------------------------------------------------------+
1 row in set (0.00 sec)

root@localhost [mysql]> select * from audit_log_filter;
+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
| NAME             | FILTER                                                                                                                                            |
+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
| log_all          | {"filter": {"log": true}}                                                                                                                         |
| log_confidential | {"filter": {"class": {"name": "table_access", "event": {"log": {"field": {"name": "table_name.str", "value": "confidential"}}, "name": "read"}}}} |
+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

root@localhost [mysql]> select * from audit_log_user;
+--------------+----------------+------------------+
| USER         | HOST           | FILTERNAME       |
+--------------+----------------+------------------+
| audit_target | localhost      | log_all          |
| audit_target | %              | log_all          |
| audit_target | 192.168.56.109 | log_all          |
| audit_target | misc02         | log_all          |
| confidential | %              | log_confidential |
| confidential | localhost      | log_confidential |
| confidential | 192.168.56.109 | log_confidential |
| confidential | misc02         | log_confidential |
+--------------+----------------+------------------+
8 rows in set (0.00 sec)

root@localhost [mysql]> 

6) 上記コマンドを実行して、別ホストからアクセスしてログを確認してみました。
Select -> Insert -> Selectの順番でログを確認しています。


confidential@192.168.56.113 [Audit]> select * from confidential;
Empty set (0.00 sec)

confidential@192.168.56.113 [Audit]> insert into confidential(memo) values('秘密の情報');
Query OK, 1 row affected (0.01 sec)

confidential@192.168.56.113 [Audit]> select * from confidential;
+-----------------+
| memo            |
+-----------------+
| 秘密の情報      |
+-----------------+
1 row in set (0.01 sec)

confidential@192.168.56.113 [Audit]> 

audit.logの中身を確認してみると。
きちんと設定したテーブルに対しての参照処理のみ記録されている事が確認出来ました。


 <AUDIT_RECORD>>
  <TIMESTAMP>2016-06-16T03:09:53 UTC</TIMESTAMP>
  <RECORD_ID>87435_2016-06-16T02:35:04</RECORD_ID>
  <NAME>TableRead</NAME>
  <CONNECTION_ID>6</CONNECTION_ID>
  <USER>confidential[confidential] @ misc02 [192.168.56.109]</USER>
  <OS_LOGIN/>
  <HOST>misc02</HOST>
  <IP>192.168.56.109</IP>
  <COMMAND_CLASS>select</COMMAND_CLASS>
  <SQLTEXT>select * from confidential</SQLTEXT>
  <DB>Audit</DB>
  <TABLE>confidential</TABLE>
 </AUDIT_RECORD>
 <AUDIT_RECORD>
  <TIMESTAMP>2016-06-16T03:10:12 UTC</TIMESTAMP>
  <RECORD_ID>87436_2016-06-16T02:35:04</RECORD_ID>
  <NAME>TableRead</NAME>
  <CONNECTION_ID>6</CONNECTION_ID>
  <USER>confidential[confidential] @ misc02 [192.168.56.109]</USER>
  <OS_LOGIN/>
  <HOST>misc02</HOST>
  <IP>192.168.56.109</IP>
  <COMMAND_CLASS>select</COMMAND_CLASS>
  <SQLTEXT>select * from confidential</SQLTEXT>
  <DB>Audit</DB>
  <TABLE>confidential</TABLE>
 </AUDIT_RECORD>

これまでより、断然監査がし易くなっているので是非検証してみて下さい。
トライアル(試用版)ダウンロード: https://www-jp.mysql.com/trials/

Enterprise Monitorも合わせて検証するとAudit Logの状況がリアルタイムで可視化出来ます。(閾値を超えたら、メールかSNMPで管理者に連絡)
index

indexlog

参考)
https://dev.mysql.com/doc/refman/5.7/en/audit-log-installation.html
http://mysqlserverteam.com/mysql-5-7-new-audit-log-filtering-feature-part-1/


MySQLで疑似的なマテリアライズド・ビューを作成

MySQLにはOracleで利用可能な、マテリアライズド・ビューは実装されてません。
その為、トリガーで対応したり、ワークテーブルを作成しておいて、定期的にデータを入れ替えるような処理で対応する必要があります。

過去の経験では、デイリー、ウイークリーランキングを作成する為に、以下のようにMySQLのEVENT SCHEDULE機能とREPLACE 構文を利用して変更されたデータを
定期的に入れ替える処理を行ないマテリアライズド・ビューの代わりに利用していました。
イベントは、イベントを作成してスケジュールします。但し、イベントスケジューラが有効になっていないかぎり実行されません。

メモ:EVENTの代わりに、LinuxのcronやWindows Task Schedulerでも良いかと思います。

■ 検証用にテーブルの作成
ここでは、City_MasterがオリジナルでCity_SnapShotはSNAPコピーとしています。
オリジナルのデータはMySQLのオフィシャルサイトからダウンロードしたWorldデータベースのCityテーブルのデータを利用しています。

root@localhost [world2]> CREATE TABLE `City_Master` (
    ->   `ID` int(11) NOT NULL AUTO_INCREMENT,
    ->   `Name` char(35) NOT NULL DEFAULT '',
    ->   `CountryCode` char(3) NOT NULL DEFAULT '',
    ->   `District` char(20) NOT NULL DEFAULT '',
    ->   `Population` int(11) NOT NULL DEFAULT '0',
    ->   `test` varchar(255) DEFAULT NULL,
    ->   PRIMARY KEY (`ID`),
    ->   KEY `idx_CountryCode` (`CountryCode`),
    ->   KEY `idx_City2_Covering` (`ID`,`Name`)
    -> ) ENGINE=InnoDB AUTO_INCREMENT=4080 DEFAULT CHARSET=utf8mb4;
Query OK, 0 rows affected (0.08 sec)

root@localhost [world2]> insert into City_Master select * from City;
Query OK, 4079 rows affected (0.15 sec)
Records: 4079  Duplicates: 0  Warnings: 0


root@localhost [world2]> CREATE TABLE `City_SnapShot` (
    ->   `ID` int(11) NOT NULL AUTO_INCREMENT,
    ->   `Name` char(35) NOT NULL DEFAULT '',
    ->   `CountryCode` char(3) NOT NULL DEFAULT '',
    ->   `District` char(20) NOT NULL DEFAULT '',
    ->   `Population` int(11) NOT NULL DEFAULT '0',
    ->   `test` varchar(255) DEFAULT NULL,
    ->   PRIMARY KEY (`ID`),
    ->   KEY `idx_CountryCode` (`CountryCode`),
    ->   KEY `idx_City2_Covering` (`ID`,`Name`)
    -> ) ENGINE=InnoDB AUTO_INCREMENT=4080 DEFAULT CHARSET=utf8mb4;
Query OK, 0 rows affected (0.02 sec)

root@localhost [world2]> 

root@localhost [world2]> REPLACE INTO City_SnapShot select ID,Name,CountryCode,District,Population,test from City_Master;
Query OK, 4079 rows affected (0.19 sec)
Records: 4079  Duplicates: 0  Warnings: 0

root@localhost [world2]> select * from City_Master where ID = 100;
+-----+---------+-------------+------------+------------+------+
| ID  | Name    | CountryCode | District   | Population | test |
+-----+---------+-------------+------------+------------+------+
| 100 | Paraná  | ARG         | Entre Rios |     207041 | NULL |
+-----+---------+-------------+------------+------------+------+
1 row in set (0.00 sec)

root@localhost [world2]> select * from City_SnapShot where ID = 100;
+-----+---------+-------------+------------+------------+------+
| ID  | Name    | CountryCode | District   | Population | test |
+-----+---------+-------------+------------+------------+------+
| 100 | Paraná  | ARG         | Entre Rios |     207041 | NULL |
+-----+---------+-------------+------------+------------+------+
1 row in set (0.00 sec)


■ マスターテーブルでデータを変更してみます。(207041->207045)した後に、
REPLACEコマンドでSnapShotテーブルへ変更を反映してみます。

メモ:PKが同じであれば、データを問題無くリプレースするかどうかの動作確認。

root@localhost [world2]> update City_Master set Population = 207045 where ID = 100;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

root@localhost [world2]> select * from City_Master where ID = 100;
+-----+---------+-------------+------------+------------+------+
| ID  | Name    | CountryCode | District   | Population | test |
+-----+---------+-------------+------------+------------+------+
| 100 | Paraná  | ARG         | Entre Rios |     207045 | NULL |
+-----+---------+-------------+------------+------------+------+
1 row in set (0.00 sec)

root@localhost [world2]> select * from City_SnapShot where ID = 100;
+-----+---------+-------------+------------+------------+------+
| ID  | Name    | CountryCode | District   | Population | test |
+-----+---------+-------------+------------+------------+------+
| 100 | Paraná  | ARG         | Entre Rios |     207041 | NULL |
+-----+---------+-------------+------------+------------+------+
1 row in set (0.00 sec)


root@localhost [world2]> REPLACE INTO City_SnapShot select ID,Name,CountryCode,District,Population,test from City_Master;         
Query OK, 4080 rows affected (0.10 sec)
Records: 4079  Duplicates: 1  Warnings: 0

root@localhost [world2]> select * from City_Master where ID = 100;
+-----+---------+-------------+------------+------------+------+
| ID  | Name    | CountryCode | District   | Population | test |
+-----+---------+-------------+------------+------------+------+
| 100 | Paraná  | ARG         | Entre Rios |     207045 | NULL |
+-----+---------+-------------+------------+------------+------+
1 row in set (0.01 sec)

root@localhost [world2]> select * from City_SnapShot where ID = 100;
+-----+---------+-------------+------------+------------+------+
| ID  | Name    | CountryCode | District   | Population | test |
+-----+---------+-------------+------------+------------+------+
| 100 | Paraná  | ARG         | Entre Rios |     207045 | NULL |
+-----+---------+-------------+------------+------------+------+
1 row in set (0.00 sec)

root@localhost [world2]> 

■ ここから、EVENTを有効にして定期的にデータが自動反映されるスケジュールを設定します。
オプションファイルへ追加


event-scheduler=ON

■ オプションファイルへの設定変更が反映されているかどうか確認。
メモ:SETコマンドで、動的にも設定可能。
event_schedulerが実行されている事を確認したら、EVENTを作成しスケジュールを設定します。


root@localhost [world2]> show variables like 'event%';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| event_scheduler | ON    |
+-----------------+-------+
1 row in set (0.00 sec)

root@localhost [world2]> show processlist;
+----+-----------------+-----------+--------+---------+------+------------------------+------------------+
| Id | User            | Host      | db     | Command | Time | State                  | Info             |
+----+-----------------+-----------+--------+---------+------+------------------------+------------------+
|  1 | event_scheduler | localhost | NULL   | Daemon  |   53 | Waiting on empty queue | NULL             |
|  4 | root            | localhost | world2 | Query   |    0 | starting               | show processlist |
+----+-----------------+-----------+--------+---------+------+------------------------+------------------+
2 rows in set (0.01 sec)

root@localhost [world2]> 



root@localhost [world2]> CREATE EVENT SNAP_SHOT_VIEW_City_Master_City_SnapShot
    ->    ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR
    ->    DO 
    ->      REPLACE INTO City_SnapShot select ID,Name,CountryCode,District,Population,test from City_Master;
Query OK, 0 rows affected (0.00 sec)

root@localhost [world2]> show events;
+--------+------------------------------------------+----------------+-----------+----------+---------------------+----------------+----------------+--------+------+---------+------------+----------------------+----------------------+--------------------+
| Db     | Name                                     | Definer        | Time zone | Type     | Execute at          | Interval value | Interval field | Starts | Ends | Status  | Originator | character_set_client | collation_connection | Database Collation |
+--------+------------------------------------------+----------------+-----------+----------+---------------------+----------------+----------------+--------+------+---------+------------+----------------------+----------------------+--------------------+
| world2 | SNAP_SHOT_VIEW_City_Master_City_SnapShot | root@localhost | SYSTEM    | ONE TIME | 2016-06-10 15:23:01 | NULL           | NULL           | NULL   | NULL | ENABLED |          1 | utf8                 | utf8_general_ci      | utf8mb4_general_ci |
+--------+------------------------------------------+----------------+-----------+----------+---------------------+----------------+----------------+--------+------+---------+------------+----------------------+----------------------+--------------------+
1 row in set (0.00 sec)

root@localhost [world2]> SELECT * FROM information_schema.EVENTS\G
*************************** 1. row ***************************
       EVENT_CATALOG: def
        EVENT_SCHEMA: world2
          EVENT_NAME: SNAP_SHOT_VIEW_City_Master_City_SnapShot
             DEFINER: root@localhost
           TIME_ZONE: SYSTEM
          EVENT_BODY: SQL
    EVENT_DEFINITION: REPLACE INTO City_SnapShot select ID,Name,CountryCode,District,Population,test from City_Master
          EVENT_TYPE: ONE TIME
          EXECUTE_AT: 2016-06-10 15:23:01
      INTERVAL_VALUE: NULL
      INTERVAL_FIELD: NULL
            SQL_MODE: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
              STARTS: NULL
                ENDS: NULL
              STATUS: ENABLED
       ON_COMPLETION: NOT PRESERVE
             CREATED: 2016-06-10 14:23:01
        LAST_ALTERED: 2016-06-10 14:23:01
       LAST_EXECUTED: NULL
       EVENT_COMMENT: 
          ORIGINATOR: 1
CHARACTER_SET_CLIENT: utf8
COLLATION_CONNECTION: utf8_general_ci
  DATABASE_COLLATION: utf8mb4_general_ci
1 row in set (0.00 sec)

root@localhost [world2]> 



■ イベントを設定し終わったので、データを変更すれば、
次回のスケジュール(2016-06-10 15:23:01)にはデータが変更される事になります。

データを一件変更してみます。

root@localhost [world2]> select * from City_Master where ID = 1;
+----+-------+-------------+----------+------------+------+
| ID | Name  | CountryCode | District | Population | test |
+----+-------+-------------+----------+------------+------+
|  1 | Kabul | AFG         | Kabol    |    1780000 | NULL |
+----+-------+-------------+----------+------------+------+
1 row in set (0.00 sec)

root@localhost [world2]> select * from City_SnapShot where ID = 1;
+----+-------+-------------+----------+------------+------+
| ID | Name  | CountryCode | District | Population | test |
+----+-------+-------------+----------+------------+------+
|  1 | Kabul | AFG         | Kabol    |    1780000 | NULL |
+----+-------+-------------+----------+------------+------+
1 row in set (0.00 sec)

root@localhost [world2]> update City_Master set Population = 1780001 where ID = 1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

■ データ反映の確認
2016-06-10 15:23:01にEVENTが実行されたので、
SnapShot側のテーブルのデータも変更されている事が確認出来ます。


root@localhost [world2]> select *,now() from City_Master where ID = 1;
+----+-------+-------------+----------+------------+------+---------------------+
| ID | Name  | CountryCode | District | Population | test | now()               |
+----+-------+-------------+----------+------------+------+---------------------+
|  1 | Kabul | AFG         | Kabol    |    1780001 | NULL | 2016-06-10 14:25:30 |
+----+-------+-------------+----------+------------+------+---------------------+
1 row in set (0.00 sec)

root@localhost [world2]> select *,now() from City_SnapShot where ID = 1;
+----+-------+-------------+----------+------------+------+---------------------+
| ID | Name  | CountryCode | District | Population | test | now()               |
+----+-------+-------------+----------+------------+------+---------------------+
|  1 | Kabul | AFG         | Kabol    |    1780000 | NULL | 2016-06-10 14:25:36 |
+----+-------+-------------+----------+------------+------+---------------------+
1 row in set (0.00 sec)

root@localhost [world2]> 


root@localhost [world2]> select *,now() from City_SnapShot where ID = 1;
+----+-------+-------------+----------+------------+------+---------------------+
| ID | Name  | CountryCode | District | Population | test | now()               |
+----+-------+-------------+----------+------------+------+---------------------+
|  1 | Kabul | AFG         | Kabol    |    1780001 | NULL | 2016-06-10 15:25:16 |
+----+-------+-------------+----------+------------+------+---------------------+
1 row in set (0.00 sec)

root@localhost [world2]> 

■ 集計表の場合
まずは、JPNの人口を合計したテーブルを作成してデータを入力しておく。
メモ:テーブルにはPKが必要です。
メモ:実際の人口は1億2000万を超えています。

root@localhost [world2]> select CountryCode,SUM(Population) from City_Master where CountryCode='JPN' group by CountryCode;
+-------------+-----------------+
| CountryCode | SUM(Population) |
+-------------+-----------------+
| JPN         |        77965107 |
+-------------+-----------------+


root@localhost [world2]> create table City_Summary (
    -> ID int(11) NOT NULL, 
    -> CountryCode char(3) NOT NULL DEFAULT '',
    -> Population int(11) NOT NULL DEFAULT '0',
    -> PRIMARY KEY (`ID`)
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Query OK, 0 rows affected (0.02 sec)


root@localhost [world2]> REPLACE INTO City_Summary select 1,CountryCode,SUM(Population) from City_Master where CountryCode='JPN' group by CountryCode;
Query OK, 1 row affected (0.01 sec)
Records: 1  Duplicates: 0  Warnings: 0

root@localhost [world2]> select * from City_Summary;
+----+-------------+------------+
| ID | CountryCode | Population |
+----+-------------+------------+
|  1 | JPN         |   77965107 |
+----+-------------+------------+
1 row in set (0.00 sec)

root@localhost [world2]> 

■ 集計表へのデータ反映
東京の人口を10名増やして、EVENTを作成してスケジュールを設定しデータが反映されるか確認してみます。

root@localhost [world2]> update City_Master set Population = 7980240 where Name = 'tokyo';
Query OK, 1 row affected (0.02 sec)
Rows matched: 1  Changed: 1  Warnings: 0

root@localhost [world2]> select * from City_Summary;
+----+-------------+------------+
| ID | CountryCode | Population |
+----+-------------+------------+
|  1 | JPN         |   77965107 |
+----+-------------+------------+
1 row in set (0.00 sec)

root@localhost [world2]> CREATE EVENT SNAP_SHOT_VIEW_City_Master_City_Summary
    ->     ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 10 MINUTE 
    ->     DO 
    ->     REPLACE INTO City_Summary select 1,CountryCode,SUM(Population) from City_Master where CountryCode='JPN' group by CountryCode;
Query OK, 0 rows affected (0.00 sec)

root@localhost [world2]> 



root@localhost [world2]> SELECT * FROM information_schema.EVENTS 
    -> where EVENT_NAME = 'SNAP_SHOT_VIEW_City_Master_City_Summary'\G
*************************** 1. row ***************************
       EVENT_CATALOG: def
        EVENT_SCHEMA: world2
          EVENT_NAME: SNAP_SHOT_VIEW_City_Master_City_Summary
             DEFINER: root@localhost
           TIME_ZONE: SYSTEM
          EVENT_BODY: SQL
    EVENT_DEFINITION: REPLACE INTO City_Summary select 1,CountryCode,SUM(Population) from City_Master where CountryCode='JPN' group by CountryCode
          EVENT_TYPE: ONE TIME
          EXECUTE_AT: 2016-06-10 15:07:09
      INTERVAL_VALUE: NULL
      INTERVAL_FIELD: NULL
            SQL_MODE: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
              STARTS: NULL
                ENDS: NULL
              STATUS: ENABLED
       ON_COMPLETION: NOT PRESERVE
             CREATED: 2016-06-10 14:57:09
        LAST_ALTERED: 2016-06-10 14:57:09
       LAST_EXECUTED: NULL
       EVENT_COMMENT: 
          ORIGINATOR: 1
CHARACTER_SET_CLIENT: utf8
COLLATION_CONNECTION: utf8_general_ci
  DATABASE_COLLATION: utf8mb4_general_ci
1 row in set (0.01 sec)

root@localhost [world2]> 

■ 集計データ結果確認
設定時間に確認してみると、集計データが反映されている事が確認出来ました。

root@localhost [world2]> select *,now() from City_Summary;
+----+-------------+------------+---------------------+
| ID | CountryCode | Population | now()               |
+----+-------------+------------+---------------------+
|  1 | JPN         |   77965107 | 2016-06-10 14:59:26 |
+----+-------------+------------+---------------------+
1 row in set (0.00 sec)

root@localhost [world2]> select *,now() from City_Summary;
+----+-------------+------------+---------------------+
| ID | CountryCode | Population | now()               |
+----+-------------+------------+---------------------+
|  1 | JPN         |   77965117 | 2016-06-10 15:07:31 |
+----+-------------+------------+---------------------+
1 row in set (0.00 sec)

root@localhost [world2]> 

■ 継続的、且つ定期的にEVENTを実行したい場合
上記の例は、1回のみ実行する方法でしたが、
一定間隔で,継続して定期的に実行するには、以下の様にEVENTを作ると良いです。


root@localhost [world2]> CREATE EVENT SNAP_SHOT_VIEW_City_Master_City_Summary
    -> ON SCHEDULE 
    -> EVERY 10 MINUTE 
    -> COMMENT 'サマリーテーブルを10分毎に更新します'
    -> DO
    -> REPLACE INTO City_Summary select 1,CountryCode,SUM(Population) from City_Master where CountryCode='JPN' group by CountryCode;
Query OK, 0 rows affected (0.00 sec)

root@localhost [world2]>  SELECT * FROM information_schema.EVENTS\G
*************************** 1. row ***************************
       EVENT_CATALOG: def
        EVENT_SCHEMA: world2
          EVENT_NAME: SNAP_SHOT_VIEW_City_Master_City_Summary
             DEFINER: root@localhost
           TIME_ZONE: SYSTEM
          EVENT_BODY: SQL
    EVENT_DEFINITION: REPLACE INTO City_Summary select 1,CountryCode,SUM(Population) from City_Master where CountryCode='JPN' group by CountryCode
          EVENT_TYPE: RECURRING
          EXECUTE_AT: NULL
      INTERVAL_VALUE: 10
      INTERVAL_FIELD: MINUTE
            SQL_MODE: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
              STARTS: 2016-06-10 15:46:29
                ENDS: NULL
              STATUS: ENABLED
       ON_COMPLETION: NOT PRESERVE
             CREATED: 2016-06-10 15:46:29
        LAST_ALTERED: 2016-06-10 15:46:29
       LAST_EXECUTED: 2016-06-10 15:46:29
       EVENT_COMMENT: サマリーテーブルを10分毎に更新します
          ORIGINATOR: 1
CHARACTER_SET_CLIENT: utf8
COLLATION_CONNECTION: utf8_general_ci
  DATABASE_COLLATION: utf8mb4_general_ci
1 row in set (0.00 sec)

root@localhost [world2]> 

Oracleのマテリアライズド・ビュー程の柔軟性は無いですが、
こんな対応方法もあるかと思いますので、使えそうでしたら是非試してみて下さい。

メモ: イベントの削除
———————-
DROP EVENT イベント名;

Triggerを利用する場合の参考)
http://www.fromdual.ch/mysql-materialized-views
http://d.hatena.ne.jp/IT7C/20100730/1280501734

参考)
13.2.8 REPLACE 構文
https://dev.mysql.com/doc/refman/5.6/ja/replace.html
13.2.5.3 INSERT … ON DUPLICATE KEY UPDATE 構文
https://dev.mysql.com/doc/refman/5.6/ja/insert-on-duplicate.html
13.1.11 CREATE EVENT 構文
https://dev.mysql.com/doc/refman/5.6/ja/create-event.html


SYSスキーマのstatement_analysisとperformance_schemaのevents_statements_historyを利用して、MySQLで簡単にSQLのパフォーマンス確認。

statement_analysis / x$statement_analysis
Description:
Lists a normalized statement view with aggregated statistics,
mimics the MySQL Enterprise Monitor Query Analysis view, ordered by the total execution time per normalized statement
https://github.com/mysql/mysql-sys

events_statements_history
events_statements_history テーブルには、スレッドごとの最新の N ステートメントイベントが格納されます。
N の値はサーバー起動時に自動サイズ設定されます。テーブルサイズを明示的に設定するには、サーバー起動時にperformance_schema_events_statements_history_sizeシステム変数を設定します。
ステートメントイベントは終了するまでテーブルに追加されません。新しいイベントが追加されたときに、テーブルがいっぱいである場合、古いイベントが破棄されます。
https://dev.mysql.com/doc/refman/5.6/ja/events-statements-history-table.html

以下、幾つかテストしてみました。データも十分に入っていないので、十分なテストでは無いですが、
挙動は把握出来るかと思いますので、実際の検証環境で確認して見てください。

【1】 JSONデータのFULLスキャンの状況確認
(1) 先ずは、既存のsys.statement_analysisの状況を確認してみます。

root@localhost [sys]> select now(),query,db,full_scan,tmp_tables,tmp_disk_tables,sort_merge_passes from sys.statement_analysis;
+---------------------+-------------------------------------------------------------------+--------------------+-----------+------------+-----------------+-------------------+
| now()               | query                                                             | db                 | full_scan | tmp_tables | tmp_disk_tables | sort_merge_passes |
+---------------------+-------------------------------------------------------------------+--------------------+-----------+------------+-----------------+-------------------+
| 2016-06-03 22:16:47 | SHOW TABLES                                                       | sys                | *         |          1 |               0 |                 0 |
| 2016-06-03 22:16:47 | SELECT `sys` . `format_stateme ... cy` , `sys` . `format_time` (  | sys                | *         |          0 |               0 |                 0 |
| 2016-06-03 22:16:47 | SHOW SCHEMAS                                                      | performance_schema | *         |          1 |               0 |                 0 |
| 2016-06-03 22:16:47 | SHOW TABLES                                                       | performance_schema | *         |          1 |               0 |                 0 |
| 2016-06-03 22:16:47 | SELECT SYSTEM_USER , HOST , `d ... != ? AND `state` NOT IN (...)  | performance_schema | *         |          2 |               2 |                 0 |
| 2016-06-03 22:16:47 | SHOW SCHEMAS                                                      | sys                | *         |          1 |               0 |                 0 |
| 2016-06-03 22:16:47 | SELECT SCHEMA ( )                                                 | performance_schema |           |          0 |               0 |                 0 |
| 2016-06-03 22:16:47 | SELECT SCHEMA ( )                                                 | NULL               |           |          0 |               0 |                 0 |
| 2016-06-03 22:16:47 | SELECT SYSTEM_USER ( )                                            | NULL               |           |          0 |               0 |                 0 |
| 2016-06-03 22:16:47 | SELECT @@`version_comment` LIMIT ?                                | NULL               |           |          0 |               0 |                 0 |
+---------------------+-------------------------------------------------------------------+--------------------+-----------+------------+-----------------+-------------------+
10 rows in set (0.00 sec)

root@localhost [sys]> 

(2) こちらのJSONデータを確認するQueryを実行してみます。

echo "INDEXの無いテーブルに対するSELECTを、TEXT型とJSONデータ型で比較します。"
echo "SELECT distinct json_extract(feature,'$.type') as feature FROM 各テーブル"
echo ""

echo "【TEXT型】"
time /usr/local/mysql/bin/mysql -u demo_user -ppassword -e "SELECT distinct json_extract(feature,'$.type') as feature FROM NEW57.features_txt;"

echo ""

echo "【JSON型】"
time /usr/local/mysql/bin/mysql -u demo_user -ppassword -e "SELECT distinct json_extract(feature,'$.type') as feature FROM NEW57.features_json;"

(3) 実行 (やっぱりJSONデータ型は、TEXT型と比較するとバイナリーで早いですね:206,000件のデータ参照)

[admin@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    0m8.147s
user    0m0.007s
sys     0m0.004s

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

real    0m1.379s
user    0m0.009s
sys     0m0.005s
[admin@misc01 SOD2015]$ 

(4) 実行結果
INDEXも無い、206,000件のデータなのでどちらも、FULLスキャン,temp table,そしてディスクのtemp tableへ変換されてますね。

root@localhost [sys]> select now(),query,db,full_scan,tmp_tables,tmp_disk_tables,sort_merge_passes from sys.statement_analysis;
+---------------------+-------------------------------------------------------------------+--------------------+-----------+------------+-----------------+-------------------+
| now()               | query                                                             | db                 | full_scan | tmp_tables | tmp_disk_tables | sort_merge_passes |
+---------------------+-------------------------------------------------------------------+--------------------+-----------+------------+-----------------+-------------------+
| 2016-06-03 22:19:02 | SELECT DISTINCTROW `json_extra ... FROM `NEW57` . `features_txt`  | NULL               | *         |          1 |               1 |                 0 | ※
| 2016-06-03 22:19:02 | SELECT DISTINCTROW `json_extra ... ROM `NEW57` . `features_json`  | NULL               | *         |          1 |               1 |                 0 | ※
| 2016-06-03 22:19:02 | SHOW TABLES                                                       | sys                | *         |          2 |               0 |                 0 |
| 2016-06-03 22:19:02 | SELECT `sys` . `format_stateme ... cy` , `sys` . `format_time` (  | sys                | *         |          0 |               0 |                 0 |
| 2016-06-03 22:19:02 | SHOW SCHEMAS                                                      | performance_schema | *         |          1 |               0 |                 0 |
| 2016-06-03 22:19:02 | SELECT SYSTEM_USER ( )                                            | NULL               |           |          0 |               0 |                 0 |
| 2016-06-03 22:19:02 | SHOW SCHEMAS                                                      | sys                | *         |          2 |               0 |                 0 |
| 2016-06-03 22:19:02 | SHOW TABLES                                                       | performance_schema | *         |          1 |               0 |                 0 |
| 2016-06-03 22:19:02 | SELECT SYSTEM_USER , HOST , `d ... != ? AND `state` NOT IN (...)  | performance_schema | *         |          2 |               2 |                 0 |
| 2016-06-03 22:19:02 | SELECT @@`version_comment` LIMIT ?                                | NULL               |           |          0 |               0 |                 0 |
| 2016-06-03 22:19:02 | SELECT SCHEMA ( )                                                 | NULL               |           |          0 |               0 |                 0 |
| 2016-06-03 22:19:02 | SELECT SCHEMA ( )                                                 | performance_schema |           |          0 |               0 |                 0 |
+---------------------+-------------------------------------------------------------------+--------------------+-----------+------------+-----------------+-------------------+
12 rows in set (0.01 sec)

root@localhost [sys]> 

【2】 JSONデータにGENERATE COLUMN(生成列)でINDEXを付与した場合の状況確認

(1) 実行スクリプト

echo "JSONデータ型のサンプルを入れたテーブル"
/usr/local/mysql/bin/mysql -u demo_user -ppassword -e "select * from NEW57.features where feature_street = '\"MARKET\"' limit 1\G"

read -p "Press [Enter] key to resume."
echo "JSONデータ型とGenerated Columnを利用したテーブル"
/usr/local/mysql/bin/mysql -u demo_user -ppassword -e "show create table NEW57.features\G"

read -p "Press [Enter] key to resume."
echo "JSONドキュメントに対して、INDEX検索が利用出来るか確認 -> where feature_street = '\"MARKET\"'"
/usr/local/mysql/bin/mysql -u demo_user -ppassword -e "explain select feature from NEW57.features where feature_street = '\"MARKET\"'\G"

(2) 実行と実行結果

[admin@misc01 SOD2015]$ ./json_and_generated_column_index.sh 
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 `idx_feature_type` (`feature_type`),
  KEY `idx_feature_street` (`feature_street`)
) ENGINE=InnoDB AUTO_INCREMENT=206561 DEFAULT CHARSET=utf8mb4
Press [Enter] key to resume.

JSONドキュメントに対して、INDEX検索が利用出来るか確認 -> where feature_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: idx_feature_street
          key: idx_feature_street
      key_len: 123
          ref: const
         rows: 808
     filtered: 100.00
        Extra: NULL
[admin@misc01 SOD2015]$ 

(3) 実行後のsys.statement_analysisを確認すると、full_scanでも無く,temp tableでの処理も無いことが確認出来る。

root@localhost [sys]> select now(),query,db,full_scan,tmp_tables,tmp_disk_tables,sort_merge_passes from sys.statement_analysis;
+---------------------+-------------------------------------------------------------------+--------------------+-----------+------------+-----------------+-------------------+
| now()               | query                                                             | db                 | full_scan | tmp_tables | tmp_disk_tables | sort_merge_passes |
+---------------------+-------------------------------------------------------------------+--------------------+-----------+------------+-----------------+-------------------+
| 2016-06-03 22:22:03 | SELECT DISTINCTROW `json_extra ... FROM `NEW57` . `features_txt`  | NULL               | *         |          1 |               1 |                 0 |
| 2016-06-03 22:22:03 | SELECT DISTINCTROW `json_extra ... ROM `NEW57` . `features_json`  | NULL               | *         |          1 |               1 |                 0 |
| 2016-06-03 22:22:03 | SELECT * FROM `NEW57` . `featu ... _extract` ( `feature` , ? ) )  | NULL               |           |          0 |               0 |                 0 | ※
| 2016-06-03 22:22:03 | SHOW TABLES                                                       | sys                | *         |          3 |               0 |                 0 |
| 2016-06-03 22:22:03 | SELECT `sys` . `format_stateme ... cy` , `sys` . `format_time` (  | sys                | *         |          0 |               0 |                 0 |
| 2016-06-03 22:22:03 | SHOW SCHEMAS                                                      | performance_schema | *         |          1 |               0 |                 0 |
| 2016-06-03 22:22:03 | SELECT SYSTEM_USER ( )                                            | NULL               |           |          0 |               0 |                 0 |
| 2016-06-03 22:22:03 | SHOW SCHEMAS                                                      | sys                | *         |          3 |               0 |                 0 |
| 2016-06-03 22:22:03 | SELECT @@`version_comment` LIMIT ?                                | NULL               |           |          0 |               0 |                 0 |
| 2016-06-03 22:22:03 | SHOW TABLES                                                       | performance_schema | *         |          1 |               0 |                 0 |
| 2016-06-03 22:22:03 | SELECT SYSTEM_USER , HOST , `d ... != ? AND `state` NOT IN (...)  | performance_schema | *         |          2 |               2 |                 0 |
| 2016-06-03 22:22:03 | EXPLAIN SELECT `feature` FROM  ... _extract` ( `feature` , ? ) )  | NULL               |           |          0 |               0 |                 0 |
| 2016-06-03 22:22:03 | SHOW CREATE TABLE `NEW57` . `f ... _extract` ( `feature` , ? ) )  | NULL               |           |          0 |               0 |                 0 |
| 2016-06-03 22:22:03 | SELECT SCHEMA ( )                                                 | NULL               |           |          0 |               0 |                 0 |
| 2016-06-03 22:22:03 | SELECT SCHEMA ( )                                                 | performance_schema |           |          0 |               0 |                 0 |
+---------------------+-------------------------------------------------------------------+--------------------+-----------+------------+-----------------+-------------------+
15 rows in set (0.00 sec)

root@localhost [sys]> 

(4) 強制的にデータのソート処理を発生させて、sys.statement_analysisにてsort_merge_passesが確認出来るか念の為確認。
group byの処理により、tmp_disk_tables、sort_merge_passes共に発生しています。


root@localhost [NEW57]> SELECT json_extract(feature,'$.properties.STREET'),count(json_extract(feature,'$.properties.STREET')) as feature FROM NEW57.features group by json_extract(feature,'$.properties.STREET');
<SNIP>
1717 rows in set (4.61 sec)

root@localhost [sys]> select now(),query,db,full_scan,tmp_tables,tmp_disk_tables,sort_merge_passes from sys.statement_analysis where db = 'NEW57';
+---------------------+-------------------------------------------------------------------+-------+-----------+------------+-----------------+-------------------+
| now()               | query                                                             | db    | full_scan | tmp_tables | tmp_disk_tables | sort_merge_passes |
+---------------------+-------------------------------------------------------------------+-------+-----------+------------+-----------------+-------------------+
| 2016-06-04 08:40:56 | SELECT `json_extract` ( `featu ... on_extract` ( `feature` , ? )  | NEW57 | *         |          1 |               1 |                 1 | ※DISK処理発生
| 2016-06-04 08:40:56 | SELECT `json_extract` ( `featu ... re` FROM `NEW57` . `features`  | NEW57 | *         |          0 |               0 |                 0 |
| 2016-06-04 08:40:56 | SHOW SCHEMAS                                                      | NEW57 | *         |          1 |               0 |                 0 |
| 2016-06-04 08:40:56 | SHOW TABLES                                                       | NEW57 | *         |          1 |               0 |                 0 |
| 2016-06-04 08:40:56 | SELECT `json_extract` ( `featu ... re` FROM `NEW57` . `features`  | NEW57 |           |          0 |               0 |                 0 |
+---------------------+-------------------------------------------------------------------+-------+-----------+------------+-----------------+-------------------+
5 rows in set (0.01 sec)

root@localhost [sys]> select SQL_TEXT,(timer_wait)/1000000000.0 "t (ms)",ROWS_EXAMINED from performance_schema.events_statements_history order by TIMER_START desc limit 10;
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------+---------------+
| SQL_TEXT                                                                                                                                                                                  | t (ms)    | ROWS_EXAMINED |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------+---------------+
| NULL                                                                                                                                                                                      |    0.0197 |             0 |
| NULL                                                                                                                                                                                      |    0.0080 |             0 |
| NULL                                                                                                                                                                                      |    0.0048 |             0 |
| NULL                                                                                                                                                                                      |    0.0039 |             0 |
| select now(),query,db,full_scan,tmp_tables,tmp_disk_tables,sort_merge_passes from sys.statement_analysis where db = 'NEW57'                                                               |    3.2530 |            25 |
| SELECT json_extract(feature,'$.properties.STREET'),count(json_extract(feature,'$.properties.STREET')) as feature FROM NEW57.features group by json_extract(feature,'$.properties.STREET') | 4606.0133 |        209994 |
| SELECT json_extract(feature,'$.properties.STREET') as feature FROM NEW57.features                                                                                                         |  559.5791 |        206560 |
| SELECT json_extract(feature,'$.properties.STREET'),count(json_extract(feature,'$.properties.STREET')) as feature FROM NEW57.features                                                      |    0.2148 |             0 |
| NULL                                                                                                                                                                                      |    0.0981 |             0 |
| SET @slave_uuid= 'b1f2d384-009f-11e6-9aa6-0800275fa837'                                                                                                                                   |    0.0996 |             0 |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------+---------------+
10 rows in set (0.00 sec)

root@localhost [sys]> 


【3】 ここからは、MySQLのオフィシャルサンプルDB(World)を利用してMySQLの挙動とパフォーマンスを確認してみます。

パターン1) Country STRAIGHT_JOIN CountryLanguage ON CountryLanguage.CountryCode

root@localhost [sys]> select now(),query,db,full_scan,tmp_tables,tmp_disk_tables,sort_merge_passes from sys.statement_analysis where db = 'world';
+---------------------+---------------+-------+-----------+------------+-----------------+-------------------+
| now()               | query         | db    | full_scan | tmp_tables | tmp_disk_tables | sort_merge_passes |
+---------------------+---------------+-------+-----------+------------+-----------------+-------------------+
| 2016-06-03 22:25:41 | SHOW TABLES   | world | *         |          2 |               0 |                 0 |
| 2016-06-03 22:25:41 | SHOW SCHEMAS  | world | *         |          1 |               0 |                 0 |
+---------------------+---------------+-------+-----------+------------+-----------------+-------------------+
2 rows in set (0.01 sec)

root@localhost [sys]>


root@localhost [world]> SELECT Language, COUNT(1) FROM Country STRAIGHT_JOIN CountryLanguage ON CountryLanguage.CountryCode = Country.Code WHERE Capital IN (SELECT Id FROM City) GROUP BY LANGUAGE;
+---------------------------+----------+
| Language                  | COUNT(1) |
+---------------------------+----------+
| Abhyasi                   |        1 |
| Acholi                    |        1 |
| Adja                      |        1 |
<SNIP>
| Zhuang                    |        1 |
| Zulu                      |        3 |
| [South]Mande              |        1 |
+---------------------------+----------+
457 rows in set (0.04 sec)

root@localhost [world]> 


root@localhost [sys]> select now(),query,db,full_scan,tmp_tables,tmp_disk_tables,sort_merge_passes from sys.statement_analysis where db = 'world';
+---------------------+-------------------------------------------------------------------+-------+-----------+------------+-----------------+-------------------+
| now()               | query                                                             | db    | full_scan | tmp_tables | tmp_disk_tables | sort_merge_passes |
+---------------------+-------------------------------------------------------------------+-------+-----------+------------+-----------------+-------------------+
| 2016-06-03 22:25:52 | SELECT LANGUAGE , COUNT (?) FR ... OM `City` ) GROUP BY LANGUAGE  | world | *         |          1 |               0 |                 0 |(1回目)
| 2016-06-03 22:25:52 | SHOW TABLES                                                       | world | *         |          2 |               0 |                 0 |
| 2016-06-03 22:25:52 | SHOW SCHEMAS                                                      | world | *         |          1 |               0 |                 0 |
+---------------------+-------------------------------------------------------------------+-------+-----------+------------+-----------------+-------------------+
3 rows in set (0.00 sec)

root@localhost [sys]> 

上記、Queryの実行プランと実行時間を確認してみます。

root@localhost [world]> explain SELECT Language, COUNT(1) FROM Country STRAIGHT_JOIN CountryLanguage ON CountryLanguage.CountryCode = Country.Code WHERE Capital IN (SELECT Id FROM City) GROUP BY LANGUAGE;
+----+-------------+-----------------+------------+--------+---------------------+-------------+---------+-----------------------+------+----------+----------------------------------------------+
| id | select_type | table           | partitions | type   | possible_keys       | key         | key_len | ref                   | rows | filtered | Extra                                        |
+----+-------------+-----------------+------------+--------+---------------------+-------------+---------+-----------------------+------+----------+----------------------------------------------+
|  1 | SIMPLE      | Country         | NULL       | ALL    | PRIMARY             | NULL        | NULL    | NULL                  |  239 |   100.00 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | City            | NULL       | eq_ref | PRIMARY             | PRIMARY     | 4       | world.Country.Capital |    1 |   100.00 | Using index                                  |
|  1 | SIMPLE      | CountryLanguage | NULL       | ref    | PRIMARY,CountryCode | CountryCode | 3       | world.Country.Code    |    4 |   100.00 | Using index                                  |
+----+-------------+-----------------+------------+--------+---------------------+-------------+---------+-----------------------+------+----------+----------------------------------------------+
3 rows in set, 1 warning (0.00 sec)

root@localhost [world]> 



root@localhost [sys]> select SQL_TEXT,(timer_wait)/1000000000.0 "t (ms)",ROWS_EXAMINED from performance_schema.events_statements_history order by TIMER_START desc limit 10;
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+---------------+
| SQL_TEXT                                                                                                                                                                    | t (ms) | ROWS_EXAMINED |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+---------------+
| SELECT Language, COUNT(1) FROM Country STRAIGHT_JOIN CountryLanguage ON CountryLanguage.CountryCode = Country.Code WHERE Capital IN (SELECT Id FROM City) GROUP BY LANGUAGE | 7.3615 |          2368 |(1回目)
| select SQL_TEXT,(timer_wait)/1000000000.0 "t (ms)",ROWS_EXAMINED from performance_schema.events_statements_history order by TIMER_START desc limit 10                       | 0.5577 |             2 |
| truncate table performance_schema.events_statements_history                                                                                                                 | 0.9153 |             0 |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+---------------+
3 rows in set (0.01 sec)

root@localhost [sys]>

パターン2) CountryLanguage STRAIGHT_JOIN Country ON CountryLanguage.CountryCode = Country.Code

root@localhost [sys]> select now(),query,db,full_scan,tmp_tables,tmp_disk_tables,sort_merge_passes from sys.statement_analysis where db = 'world';
+---------------------+-------------------------------------------------------------------+-------+-----------+------------+-----------------+-------------------+
| now()               | query                                                             | db    | full_scan | tmp_tables | tmp_disk_tables | sort_merge_passes |
+---------------------+-------------------------------------------------------------------+-------+-----------+------------+-----------------+-------------------+
| 2016-06-03 22:28:15 | SELECT LANGUAGE , COUNT (?) FR ... OM `City` ) GROUP BY LANGUAGE  | world | *         |          1 |               0 |                 0 |
| 2016-06-03 22:28:15 | EXPLAIN SELECT LANGUAGE , COUN ... OM `City` ) GROUP BY LANGUAGE  | world | *         |          1 |               0 |                 0 |
| 2016-06-03 22:28:15 | SHOW TABLES                                                       | world | *         |          2 |               0 |                 0 |
| 2016-06-03 22:28:15 | SHOW SCHEMAS                                                      | world | *         |          1 |               0 |                 0 |
+---------------------+-------------------------------------------------------------------+-------+-----------+------------+-----------------+-------------------+
4 rows in set (0.01 sec)

root@localhost [sys]>


root@localhost [world]> SELECT Language, COUNT(1) FROM CountryLanguage STRAIGHT_JOIN Country ON CountryLanguage.CountryCode = Country.Code WHERE Capital IN (SELECT Id FROM City) GROUP BY LANGUAGE;
+---------------------------+----------+
| Language                  | COUNT(1) |
+---------------------------+----------+
| Abhyasi                   |        1 |
| Acholi                    |        1 |
| Adja                      |        1 |
<SNIP>
| Zhuang                    |        1 |
| Zulu                      |        3 |
| [South]Mande              |        1 |
+---------------------------+----------+
457 rows in set (0.01 sec)

root@localhost [sys]> select now(),query,db,full_scan,tmp_tables,tmp_disk_tables,sort_merge_passes from sys.statement_analysis where db = 'world';
+---------------------+-------------------------------------------------------------------+-------+-----------+------------+-----------------+-------------------+
| now()               | query                                                             | db    | full_scan | tmp_tables | tmp_disk_tables | sort_merge_passes |
+---------------------+-------------------------------------------------------------------+-------+-----------+------------+-----------------+-------------------+
| 2016-06-03 22:29:13 | SELECT LANGUAGE , COUNT (?) FR ... OM `City` ) GROUP BY LANGUAGE  | world | *         |          1 |               0 |                 0 |(1回目)
| 2016-06-03 22:29:13 | SELECT LANGUAGE , COUNT (?) FR ... OM `City` ) GROUP BY LANGUAGE  | world |           |          1 |               0 |                 0 |(2回目)
| 2016-06-03 22:29:13 | EXPLAIN SELECT LANGUAGE , COUN ... OM `City` ) GROUP BY LANGUAGE  | world | *         |          1 |               0 |                 0 |
| 2016-06-03 22:29:13 | SHOW TABLES                                                       | world | *         |          2 |               0 |                 0 |
| 2016-06-03 22:29:13 | SHOW SCHEMAS                                                      | world | *         |          1 |               0 |                 0 |
+---------------------+-------------------------------------------------------------------+-------+-----------+------------+-----------------+-------------------+
5 rows in set (0.01 sec)

root@localhost [sys]> 

上記、Queryの実行プランと実行時間を確認してみます。
行数は、多いですがFULL SCANは発生していません、また時間も若干早いです。(但し、何回も実施していないので確かではありません、但しこのサイズではそれ程大きく変わらない事は確かです。)

root@localhost [world]> explain SELECT Language, COUNT(1) FROM CountryLanguage STRAIGHT_JOIN Country ON CountryLanguage.CountryCode = Country.Code WHERE Capital IN (SELECT Id FROM City) GROUP BY LANGUAGE;
+----+-------------+-----------------+------------+--------+---------------------+-------------+---------+-----------------------------------+------+----------+----------------------------------------------+
| id | select_type | table           | partitions | type   | possible_keys       | key         | key_len | ref                               | rows | filtered | Extra                                        |
+----+-------------+-----------------+------------+--------+---------------------+-------------+---------+-----------------------------------+------+----------+----------------------------------------------+
|  1 | SIMPLE      | CountryLanguage | NULL       | index  | PRIMARY,CountryCode | CountryCode | 3       | NULL                              |  984 |   100.00 | Using index; Using temporary; Using filesort |
|  1 | SIMPLE      | Country         | NULL       | eq_ref | PRIMARY             | PRIMARY     | 3       | world.CountryLanguage.CountryCode |    1 |   100.00 | Using where                                  |
|  1 | SIMPLE      | City            | NULL       | eq_ref | PRIMARY             | PRIMARY     | 4       | world.Country.Capital             |    1 |   100.00 | Using index                                  |
+----+-------------+-----------------+------------+--------+---------------------+-------------+---------+-----------------------------------+------+----------+----------------------------------------------+
3 rows in set, 1 warning (0.00 sec)

root@localhost [world]> 

root@localhost [sys]> select SQL_TEXT,(timer_wait)/1000000000.0 "t (ms)",ROWS_EXAMINED from performance_schema.events_statements_history order by TIMER_START desc limit 10;
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+---------------+
| SQL_TEXT                                                                                                                                                                    | t (ms) | ROWS_EXAMINED |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+---------------+
| SELECT Language, COUNT(1) FROM CountryLanguage STRAIGHT_JOIN Country ON CountryLanguage.CountryCode = Country.Code WHERE Capital IN (SELECT Id FROM City) GROUP BY LANGUAGE | 7.0868 |          3865 |(2回目)
| select SQL_TEXT,(timer_wait)/1000000000.0 "t (ms)",ROWS_EXAMINED from performance_schema.events_statements_history order by TIMER_START desc limit 10                       | 1.5986 |             6 |
| SELECT Language, COUNT(1) FROM Country STRAIGHT_JOIN CountryLanguage ON CountryLanguage.CountryCode = Country.Code WHERE Capital IN (SELECT Id FROM City) GROUP BY LANGUAGE | 7.3615 |          2368 |(1回目)
| select SQL_TEXT,(timer_wait)/1000000000.0 "t (ms)",ROWS_EXAMINED from performance_schema.events_statements_history order by TIMER_START desc limit 10                       | 0.5577 |             2 |
| truncate table performance_schema.events_statements_history                                                                                                                 | 0.9153 |             0 |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+---------------+
5 rows in set (0.00 sec)

root@localhost [sys]>

パターン3) Country JOIN CountryLanguage ON CountryLanguage.CountryCode = Country.Code
ヒント無しなので、オプティマイザー次第

root@localhost [sys]> select now(),query,db,full_scan,tmp_tables,tmp_disk_tables,sort_merge_passes from sys.statement_analysis where db = 'world';
+---------------------+-------------------------------------------------------------------+-------+-----------+------------+-----------------+-------------------+
| now()               | query                                                             | db    | full_scan | tmp_tables | tmp_disk_tables | sort_merge_passes |
+---------------------+-------------------------------------------------------------------+-------+-----------+------------+-----------------+-------------------+
| 2016-06-03 22:33:16 | SELECT LANGUAGE , COUNT (?) FR ... OM `City` ) GROUP BY LANGUAGE  | world | *         |          1 |               0 |                 0 |
| 2016-06-03 22:33:16 | SELECT LANGUAGE , COUNT (?) FR ... OM `City` ) GROUP BY LANGUAGE  | world |           |          1 |               0 |                 0 |
| 2016-06-03 22:33:16 | EXPLAIN SELECT LANGUAGE , COUN ... OM `City` ) GROUP BY LANGUAGE  | world | *         |          1 |               0 |                 0 |
| 2016-06-03 22:33:16 | SHOW TABLES                                                       | world | *         |          2 |               0 |                 0 |
| 2016-06-03 22:33:16 | EXPLAIN SELECT LANGUAGE , COUN ... OM `City` ) GROUP BY LANGUAGE  | world |           |          1 |               0 |                 0 |
| 2016-06-03 22:33:16 | SHOW SCHEMAS                                                      | world | *         |          1 |               0 |                 0 |
+---------------------+-------------------------------------------------------------------+-------+-----------+------------+-----------------+-------------------+
6 rows in set (0.01 sec)

root@localhost [sys]>


root@localhost [world]> SELECT Language, COUNT(1) FROM Country JOIN CountryLanguage ON CountryLanguage.CountryCode = Country.Code WHERE Capital IN (SELECT Id FROM City) GROUP BY LANGUAGE;
+---------------------------+----------+
| Language                  | COUNT(1) |
+---------------------------+----------+
| Abhyasi                   |        1 |
| Acholi                    |        1 |
| Adja                      |        1 |
<SNIP>
| Zhuang                    |        1 |
| Zulu                      |        3 |
| [South]Mande              |        1 |
+---------------------------+----------+
457 rows in set (0.01 sec)

root@localhost [world]> 

root@localhost [sys]> select now(),query,db,full_scan,tmp_tables,tmp_disk_tables,sort_merge_passes from sys.statement_analysis where db = 'world';
+---------------------+-------------------------------------------------------------------+-------+-----------+------------+-----------------+-------------------+
| now()               | query                                                             | db    | full_scan | tmp_tables | tmp_disk_tables | sort_merge_passes |
+---------------------+-------------------------------------------------------------------+-------+-----------+------------+-----------------+-------------------+
| 2016-06-03 22:33:29 | SELECT LANGUAGE , COUNT (?) FR ... OM `City` ) GROUP BY LANGUAGE  | world | *         |          1 |               0 |                 0 |(1回目)
| 2016-06-03 22:33:29 | SELECT LANGUAGE , COUNT (?) FR ... OM `City` ) GROUP BY LANGUAGE  | world |           |          1 |               0 |                 0 |(2回目)
| 2016-06-03 22:33:29 | SELECT LANGUAGE , COUNT (?) FR ... OM `City` ) GROUP BY LANGUAGE  | world | *         |          1 |               0 |                 0 |(3回目)
| 2016-06-03 22:33:29 | EXPLAIN SELECT LANGUAGE , COUN ... OM `City` ) GROUP BY LANGUAGE  | world | *         |          1 |               0 |                 0 |
| 2016-06-03 22:33:29 | SHOW TABLES                                                       | world | *         |          2 |               0 |                 0 |
| 2016-06-03 22:33:29 | EXPLAIN SELECT LANGUAGE , COUN ... OM `City` ) GROUP BY LANGUAGE  | world |           |          1 |               0 |                 0 |
| 2016-06-03 22:33:29 | SHOW SCHEMAS                                                      | world | *         |          1 |               0 |                 0 |
+---------------------+-------------------------------------------------------------------+-------+-----------+------------+-----------------+-------------------+
7 rows in set (0.01 sec)

root@localhost [sys]> 

上記、Queryの実行プランと実行時間を確認してみます。(今回はヒントを付けてませんが、1回目と同じ実行プランになりました)
よって、EXPLAINも時間も殆ど同じです。

root@localhost [world]> explain SELECT Language, COUNT(1) FROM Country JOIN CountryLanguage ON CountryLanguage.CountryCode = Country.Code WHERE Capital IN (SELECT Id FROM City) GROUP BY LANGUAGE;
+----+-------------+-----------------+------------+--------+---------------------+-------------+---------+-----------------------+------+----------+----------------------------------------------+
| id | select_type | table           | partitions | type   | possible_keys       | key         | key_len | ref                   | rows | filtered | Extra                                        |
+----+-------------+-----------------+------------+--------+---------------------+-------------+---------+-----------------------+------+----------+----------------------------------------------+
|  1 | SIMPLE      | Country         | NULL       | ALL    | PRIMARY             | NULL        | NULL    | NULL                  |  239 |   100.00 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | City            | NULL       | eq_ref | PRIMARY             | PRIMARY     | 4       | world.Country.Capital |    1 |   100.00 | Using index                                  |
|  1 | SIMPLE      | CountryLanguage | NULL       | ref    | PRIMARY,CountryCode | CountryCode | 3       | world.Country.Code    |    4 |   100.00 | Using index                                  |
+----+-------------+-----------------+------------+--------+---------------------+-------------+---------+-----------------------+------+----------+----------------------------------------------+
3 rows in set, 1 warning (0.01 sec)

root@localhost [world]> 


root@localhost [sys]> select SQL_TEXT,(timer_wait)/1000000000.0 "t (ms)",ROWS_EXAMINED from performance_schema.events_statements_history order by TIMER_START desc limit 10;
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+---------------+
| SQL_TEXT                                                                                                                                                                    | t (ms) | ROWS_EXAMINED |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+---------------+
| SELECT Language, COUNT(1) FROM Country JOIN CountryLanguage ON CountryLanguage.CountryCode = Country.Code WHERE Capital IN (SELECT Id FROM City) GROUP BY LANGUAGE          | 7.3393 |          2368 |(3回目)
| select SQL_TEXT,(timer_wait)/1000000000.0 "t (ms)",ROWS_EXAMINED from performance_schema.events_statements_history order by TIMER_START desc limit 10                       | 0.8451 |            10 |
| SELECT Language, COUNT(1) FROM CountryLanguage STRAIGHT_JOIN Country ON CountryLanguage.CountryCode = Country.Code WHERE Capital IN (SELECT Id FROM City) GROUP BY LANGUAGE | 7.0868 |          3865 |(2回目)
| select SQL_TEXT,(timer_wait)/1000000000.0 "t (ms)",ROWS_EXAMINED from performance_schema.events_statements_history order by TIMER_START desc limit 10                       | 1.5986 |             6 |
| SELECT Language, COUNT(1) FROM Country STRAIGHT_JOIN CountryLanguage ON CountryLanguage.CountryCode = Country.Code WHERE Capital IN (SELECT Id FROM City) GROUP BY LANGUAGE | 7.3615 |          2368 |(1回目)
| select SQL_TEXT,(timer_wait)/1000000000.0 "t (ms)",ROWS_EXAMINED from performance_schema.events_statements_history order by TIMER_START desc limit 10                       | 0.5577 |             2 |
| truncate table performance_schema.events_statements_history                                                                                                                 | 0.9153 |             0 |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+---------------+
7 rows in set (0.00 sec)

root@localhost [sys]> 

【参考】
■ この動画とPDFは参考になる良い資料です。
https://community.oracle.com/docs/DOC-997564

■ こちらのツールを利用すると複数MySQLのシステムとSQLを監視する事が出来ます。
簡単にGUIベースで確認して管理コスト削減したいたい場合はお勧めします。
https://www-jp.mysql.com/products/enterprise/monitor.html


MySQL Shell経由でPythonで書いた処理をそのまま流し込めるので、
Twitter APIからJSONデータを取得して100件程データベースに流し込むデモを行いました。
PS: ネットワークがなぜか、共有WIFI、プライベートWIFI共に調子が悪く微妙な感じになってしまいましたが。。。

JSONデータ型、Generated Column(生成列)、MySQL Shellの挙動を簡易的にデモするものなので内容的には微妙ですが、
もしAPI経由でJSONデータを取得して、バッチ処理で定期的にサービスで使えそうなデータを取得して、
データを蓄積したり検索したい場合などに使えるかもしれません。

demo

————————————————————————
1) Create a Sample Table for Importing Data from Twitter API
————————————————————————
name列は、Tweetした人の名前が入ります。
text列は、Tweetしたコメントが入ります。


Create Table: CREATE TABLE `X_PYTHON` (
  `doc` json DEFAULT NULL,
  `_id` varchar(32) GENERATED ALWAYS AS (json_unquote(json_extract(`doc`,'$._id'))) STORED NOT NULL,
  `name` varchar(64) GENERATED ALWAYS AS (json_unquote(json_extract(`doc`,'$.user.name'))) STORED,
  `text` varchar(512) GENERATED ALWAYS AS (json_unquote(json_extract(`doc`,'$.text'))) STORED,
  UNIQUE KEY `_id` (`_id`),
  KEY `idx_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

————————————————————————
2) Create python file ( demo_python_twitter.py )
————————————————————————
デモ用サンプルなので色々とコメントアウトしてます。またエラー処理も入れてません。
動作確認のみでご利用下さい。
※ Twitterキー、スキーマ、アカウントに関しては、適宜変更して下さい。
※ 必要に応じて、”pip install requests-oauthlib”でOauthもインストールしておいてください。


# coding: utf-8

print "======================================================"
print "MySQL5.7.12 Basic CRUD Operations by Python"
print "MySQL Innovation Daysデモ"
print "======================================================"

from requests_oauthlib import OAuth1Session
import json
import mysqlx

##############################################################
#    This section is just used for my private account.
##############################################################

api_key      = "Please put your own key"
api_secret   = "Please put your own key"
token        = "Please put your own key"
token_secret = "Please put your own key"

##############################################################
#    This section is API and Auth.
##############################################################

url = "https://api.twitter.com/1.1/statuses/home_timeline.json"
params = {'count':'100',}

auth = OAuth1Session(api_key, api_secret, token, token_secret)
res = auth.get(url, params = params)

##############################################################
#     Connect Session to the MySQL Instance.
##############################################################

if res.status_code == 200: # In case of successfully connect to API

 mySession = mysqlx.getSession({
 'host': 'localhost', 'port': 33060,
 'dbUser': 'demo_user', 'dbPassword': 'password'} )
 myDb = mySession.getSchema('NEW57')


### Create a new collection 'my_collection' ###
### This section is turned off for demo.    ###
# myColl = myDb.createCollection('X_PYTHON')


### Insert documents ###

 timeline = json.loads(res.text)
 for tweet in timeline:
   myDb.X_PYTHON.add(tweet).execute()
#  myDb.X_PYTHON.add(tweet).executeAsync() # ASYNCはmysqlshでは対象外.
#  print(tweet["text"])


####################################################
###         Drop the collection(Table)
####################################################
# mySession.dropCollection('NEW57','X_PYTHON')

else: # 失敗した場合
        print ("Error: %d" % req.status_code)

————————————————————————
3) Please Execute the Script through mysqlsh
————————————————————————
こちらは、Pythonモードで処理しています。


mysqlsh --py < demo_python_twitter.py

————————————————————————
4) You can find who is the most active user in twitter.
————————————————————————
mysqlshではパイプでつないで、リダイレクトする事が出来ます。


echo "select name,count(name) from X_PYTHON group by name order by count(name) desc limit 10;" | mysqlsh -u demo_user -ppassword --sql --schema=NEW57

実行結果(直近100件のTweet件数毎のデータ確認)


mysqlx: [Warning] Using a password on the command line interface can be insecure.
+---------------------------------------+-------------+
| name                                  | count(name) |
+---------------------------------------+-------------+
<snip>
| Tony Darnell                          |          13 |
| Giuseppe Maxia                        |           2 |
| planetmysql                           |           2 |
<snip>

name以外にtextにも生成列を設定しているので、コメントをフィルターする事も出来ます。
簡易デモなので何ですが、実用的な用途があれば簡単にJSONデータ処理出来るので色々なケースで使えるかもしれません。


root@localhost [NEW57]> desc X_PYTHON;
+-------+--------------+------+-----+---------+------------------+
| Field | Type         | Null | Key | Default | Extra            |
+-------+--------------+------+-----+---------+------------------+
| doc   | json         | YES  |     | NULL    |                  |
| _id   | varchar(32)  | NO   | PRI | NULL    | STORED GENERATED |
| name  | varchar(64)  | YES  | MUL | NULL    | STORED GENERATED |
| text  | varchar(512) | YES  |     | NULL    | STORED GENERATED |
+-------+--------------+------+-----+---------+------------------+
4 rows in set (0.00 sec)

root@localhost [NEW57]> 

【補足資料】
先日、MyNA(MySQL User Group)のイベントでMySQL AS Document Storeのデモした時の資料です。


先日は、mysqlxプラグインをMySQL Shellから処理して基本動作確認しました。
mysqlxとMySQL Shell初期設定と基本動作確認
本日は、mysqlxに対応しているConnector/Node.jsからMySQLにJSONデータを処理を確認してみました。
基本的には、JohannesさんがMySQL Server Blogに書いた記事をベースに検証しています。
http://mysqlserverteam.com/mysql-5-7-12-part-5-connectornode-js/

【mysqlxとConnector/Node.jsを利用する為の前提条件】
MySQL 5.7.12 or higher, with the X plugin enabled
Node.JS 4.2

Download Connector/Node.js
~概要~
Connector/Node.js is the official Node.js driver for MySQL.
MySQL Connector/Node.js is an native asychronous promise-based client library for the of
MySQL 5.7.12+ providing New CRUD APIs for Document and Relational development

http://dev.mysql.com/downloads/connector/nodejs/

設定前の各種バージョン確認


[root@misc01 nodejs]# node -v
v4.4.3
[root@misc01 nodejs]# npm -v
2.15.1
[root@misc01 nodejs]# 

admin@192.168.56.113 [NEW57]> select @@version;
+-------------------------------------------+
| @@version                                 |
+-------------------------------------------+
| 5.7.12-enterprise-commercial-advanced-log |
+-------------------------------------------+
1 row in set (0.01 sec)

admin@192.168.56.113 [NEW57]> select PLUGIN_NAME,PLUGIN_VERSION,PLUGIN_STATUS,PLUGIN_TYPE_VERSION from information_schema.plugins
    -> where PLUGIN_NAME = 'mysqlx';
+-------------+----------------+---------------+---------------------+
| PLUGIN_NAME | PLUGIN_VERSION | PLUGIN_STATUS | PLUGIN_TYPE_VERSION |
+-------------+----------------+---------------+---------------------+
| mysqlx      | 1.0            | ACTIVE        | 50712.0             |
+-------------+----------------+---------------+---------------------+
1 row in set (0.01 sec)

admin@192.168.56.113 [NEW57]> 

ダウンロード
node.jsもMySQLもコネクター対応している事が確認出来たので、コネクターをダウンロードしてインストールしてみます。


[root@misc01 nodejs]# wget http://dev.mysql.com/get/Downloads/Connector-Nodejs/mysql-connector-nodejs-1.0.2.tar.gz
--2016-04-18 11:00:12--  http://dev.mysql.com/get/Downloads/Connector-Nodejs/mysql-connector-nodejs-1.0.2.tar.gz
dev.mysql.com (dev.mysql.com) をDNSに問いあわせています... 137.254.60.11
dev.mysql.com (dev.mysql.com)|137.254.60.11|:80 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 302 Found
場所: http://cdn.mysql.com//Downloads/Connector-Nodejs/mysql-connector-nodejs-1.0.2.tar.gz [続く]
--2016-04-18 11:00:18--  http://cdn.mysql.com//Downloads/Connector-Nodejs/mysql-connector-nodejs-1.0.2.tar.gz
cdn.mysql.com (cdn.mysql.com) をDNSに問いあわせています... 104.78.21.123
cdn.mysql.com (cdn.mysql.com)|104.78.21.123|:80 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 121705 (119K) [application/x-tar-gz]
`mysql-connector-nodejs-1.0.2.tar.gz' に保存中
100%[==============================================================================================>] 121,705      157KB/s 時間 0.8s   
2016-04-18 11:00:19 (157 KB/s) - `mysql-connector-nodejs-1.0.2.tar.gz' へ保存完了 [121705/121705]
[root@misc01 nodejs]# 

npmを使用してインストール
http://dev.mysql.com/doc/dev/connector-nodejs/
http://dev.mysql.com/doc/dev/connector-nodejs/tutorial-Getting_Started.html


[root@misc01 nodejs]# npm install mysql-connector-nodejs-1.0.2.tar.gz
mysqlx@1.0.2 node_modules/mysqlx
[root@misc01 nodejs]# 

シェルのサンプルを利用した基本動作確認

[root@misc01 nodejs]# cat sample_node_X_API.js 
const mysqlx = require('mysqlx');

mysqlx.getSession({
    host: 'localhost',
    port: 33060,
    dbUser: 'demo_user',
    dbPassword: 'password'
}).then(function (session) {
    return session.createSchema("test_schema").then(function (schema) {
        return schema.createCollection("myCollection");
    }).then(function (collection) {
        return Promise.all([
            collection.add(
                {baz: { foo: "bar"}},
                {foo: { bar: "baz"}}
            ).execute(),
            collection.find("$.baz.foo == 'bar'").execute(function (row) {
                console.log("Row: %j", row);
            }).then(function (res) {
                console.log("Collection find done!");
            }),
            collection.remove("($.foo.bar) == 'baz'").execute().then(function () {
                console.log("Document deleted");
            }),
            collection.drop()
        ]);
    }).then(function () {
        return session.dropSchema("test_schema");
    }).then(function () {
        return session.close();
    });
}).catch(function (err) {
    console.log(err.stack);
    process.exit();
});

上記スクリプトを実行


[root@misc01 nodejs]# node sample_X_API.js 
Row: {"_id":"d0ef5b1d-86e6-34b2-5794-3ebcab02","baz":{"foo":"bar"}}
Collection find done!
Document deleted
[root@misc01 nodejs]# 

実行すると、以下のオブジェクトとデータがmysqlx経由(33060)でjavascriptから登録されている

admin@192.168.56.113 [test_schema]> show tables;
+-----------------------+
| Tables_in_test_schema |
+-----------------------+
| myCollection          |
+-----------------------+
1 row in set (0.01 sec)

admin@192.168.56.113 [test_schema]> select * from myCollection;
+--------------------------------------------------------------------+----------------------------------+
| doc                                                                | _id                              |
+--------------------------------------------------------------------+----------------------------------+
| {"_id": "21dddfdd-2d4e-3cf1-fc5f-05a0e9ea", "foo": {"bar": "baz"}} | 21dddfdd-2d4e-3cf1-fc5f-05a0e9ea |
| {"_id": "7a7a7497-95c8-b7e7-fa15-064a8aba", "baz": {"foo": "bar"}} | 7a7a7497-95c8-b7e7-fa15-064a8aba |
+--------------------------------------------------------------------+----------------------------------+
2 rows in set (0.00 sec)

admin@192.168.56.113 [test_schema]> 

MySQLXのClassは以下のページを参照してください。
http://dev.mysql.com/doc/dev/connector-nodejs/NodeSession.html

その他、幾つかのパターンを検証してみましたが、node.js経由でJSONドキュメントデータをプラグイン経由で処理する事が可能なので、
JSONドキュメント処理をXプロトコル経由で高速に処理出来そうです。ただ、SQL処理とSQLX経由の処理に関しては、自分の方では実際のベンチマークは行っていないので、
Dimitriさんがブログで結果を発表してくれるのを待とうかと思います。
まだリリース間もないので、色々と情報を集めて紹介出来ればと思います。


先日、リリースされたMySQL5.7.12に含まれるmysqlxプラグインと、
同時にリリースされた、MySQL Shellの初期設定と基本動作確認を確認してみました。
基本的にこれらは、MySQL5.7で追加されたJSONデータ型を含むスキーマレスなドキュメントデータを、
mysqlxプラグインを利用する事でより柔軟に処理出来るようにする為に追加され、
MySQLをドキュメントデータベースとしてより利用し易くする為に追加された機能となっています。

MySQL Shellは、MySQLサーバの開発と管理をサポートする、
JavaScript、Python、SQLの対話型のインタフェースをサポートするMySQLの新しいコンポーネント。
データのクエリと更新処理だけでなく、様々な管理操作を実行する為にMySQLのシェルを使用することができます。
※MySQL Shellを利用する為には、事前にMySQL5.7.12以降に含まれているXプラグインをインストールしておく必要があります。

Xプラグイン
Xプロトコルを使用して通信を可能にするMySQLサーバプラグイン。
X DevAPIを実装するクライアントをサポートし、ドキュメントストアとしてMySQLを使用することができます。

Xプロトコル
Xプロトコルは、Xプラグインを実行しているMySQLサーバーと通信します。
Xプロトコルは、SSL経由でCRUDとSQL操作、認証の両方をサポートしていて、
コマンドのストリーミング処理を可能にし、プロトコルとメッセージレイヤ上に拡張可能。

root@localhost [information_schema]> select PLUGIN_NAME,PLUGIN_VERSION,PLUGIN_DESCRIPTION from plugins
    -> where PLUGIN_NAME = 'mysqlx';
+-------------+----------------+--------------------+
| PLUGIN_NAME | PLUGIN_VERSION | PLUGIN_DESCRIPTION |
+-------------+----------------+--------------------+
| mysqlx      | 1.0            | X Plugin for MySQL |
+-------------+----------------+--------------------+
1 row in set (0.00 sec)

root@localhost [information_schema]> 

【X Pluginインストール】
参照:http://dev.mysql.com/doc/refman/5.7/en/x-plugin-installation.html

通常通り、INSTALL PLUGINコマンドでインストール

root@localhost [mysql]> INSTALL PLUGIN mysqlx SONAME 'mysqlx.so';
Query OK, 0 rows affected (0.25 sec)

root@localhost [mysql]> show plugins;
+----------------------------+----------+--------------------+-------------------+-------------+
| Name                       | Status   | Type               | Library           | License     |
+----------------------------+----------+--------------------+-------------------+-------------+
| binlog                     | ACTIVE   | STORAGE ENGINE     | NULL              | PROPRIETARY |
| mysql_native_password      | ACTIVE   | AUTHENTICATION     | NULL              | PROPRIETARY |
| sha256_password            | ACTIVE   | AUTHENTICATION     | NULL              | PROPRIETARY |
| InnoDB                     | ACTIVE   | STORAGE ENGINE     | NULL              | PROPRIETARY |
| INNODB_TRX                 | ACTIVE   | INFORMATION SCHEMA | NULL              | PROPRIETARY |
| INNODB_LOCKS               | ACTIVE   | INFORMATION SCHEMA | NULL              | PROPRIETARY |
| INNODB_LOCK_WAITS          | ACTIVE   | INFORMATION SCHEMA | NULL              | PROPRIETARY |
| INNODB_CMP                 | ACTIVE   | INFORMATION SCHEMA | NULL              | PROPRIETARY |
<SNIP>
| MyISAM                     | ACTIVE   | STORAGE ENGINE     | NULL              | PROPRIETARY |
| MEMORY                     | ACTIVE   | STORAGE ENGINE     | NULL              | PROPRIETARY |
| CSV                        | ACTIVE   | STORAGE ENGINE     | NULL              | PROPRIETARY |
| BLACKHOLE                  | ACTIVE   | STORAGE ENGINE     | NULL              | PROPRIETARY |
| partition                  | ACTIVE   | STORAGE ENGINE     | NULL              | PROPRIETARY |
| FEDERATED                  | DISABLED | STORAGE ENGINE     | NULL              | PROPRIETARY |
| ARCHIVE                    | ACTIVE   | STORAGE ENGINE     | NULL              | PROPRIETARY |
| ngram                      | ACTIVE   | FTPARSER           | NULL              | PROPRIETARY |
| mecab                      | ACTIVE   | FTPARSER           | libpluginmecab.so | PROPRIETARY |
| MYSQL_FIREWALL             | ACTIVE   | AUDIT              | firewall.so       | PROPRIETARY |
| MYSQL_FIREWALL_USERS       | ACTIVE   | INFORMATION SCHEMA | firewall.so       | PROPRIETARY |
| MYSQL_FIREWALL_WHITELIST   | ACTIVE   | INFORMATION SCHEMA | firewall.so       | PROPRIETARY |
| mysqlx                     | ACTIVE   | DAEMON             | mysqlx.so         | PROPRIETARY |
+----------------------------+----------+--------------------+-------------------+-------------+
49 rows in set (0.00 sec)

root@localhost [mysql]> 

【X Plugin オプションと変数について】
設定パラメータに関しては、此方を参照下さい。
http://dev.mysql.com/doc/refman/5.7/en/x-plugin-option-variable-reference.html

【接続方法】
既に、mysqlshをインストール済みなので –sqlオプションを仕様してSQLを流し込んでみる。
mysqlxのPort33060(Default:mysqlx_port)から、ローカルのMySQLにアクセスしてSQLを実行しています。

【サンプルデータベース作成】
参照:
http://downloads.mysql.com/docs/world_x-db.zip
http://dev.mysql.com/doc/refman/5.7/en/mysql-shell-tutorial-javascript-download.html

mysqlsh経由でサンプルデータベースの作成して、mysqlクライアントで接続してスキーマとテーブルの確認

[root@misc01 MID2016]# mysqlsh -u admin -p --sql --recreate-schema world_x < world_x.sql
Enter password: 
Recreating schema world_x...

[root@misc01 MID2016]# mysql -u root -p -e "show databases like 'world%'"
Enter password: 
+-------------------+
| Database (world%) |
+-------------------+
| world             |
| world2            |
| world_x           |
+-------------------+
[root@misc01 MID2016]# mysql -u root -p -e "show tables from world_x"
Enter password: 
+-------------------+
| Tables_in_world_x |
+-------------------+
| City              |
| Country           |
| CountryInfo       |
| CountryLanguage   |
+-------------------+

【接続モード】
参考) 接続方法としては、現状では、以下のモードを選択できるようです。

# mysqlsh --help
MySQL Shell 1.0.3 Development Preview

<SNIP>

  --sql                    Start in SQL mode using a node session.
  --sqlc                   Start in SQL mode using a classic session.
  --js                     Start in JavaScript mode.
  --py                     Start in Python mode.

<SNIP>

こちらでは、mysqlsh経由でjava scriptモードの状態でJSONデータを処理してみます。


[root@misc01 MID2016]# mysqlsh -u admin -p 
Creating an X Session to admin@localhost:33060
Enter password: 
No default schema selected.

Welcome to MySQL Shell 1.0.3 Development Preview

Copyright (c) 2016, 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', '\h' or '\?' for help.

Currently in JavaScript mode. Use \sql to switch to SQL mode and execute queries.
mysql-js> news_collection = session.getSchema('NEW57').createCollection("X_JSON");
<Collection:X_JSON>
mysql-js> news_collection.add({"id": 1, "name": "Document Data", "price": 60000, "Conditions": ["NEW", 2016]});
Query OK, 1 item affected (0.01 sec)

mysql-js> news_collection.find('name like :n').bind('n','Document%');
[
    {
        "Conditions": [
            "NEW",
            2016
        ],
        "_id": "26c8af795703e611630c0800279cea3c",
        "id": 1,
        "name": "Document Data",
        "price": 60000
    }
]
1 document in set (0.03 sec)

mysql-js>  

MySQLに接続してデータを確認した状態


root@localhost [NEW57]> desc X_JSON;
+-------+-------------+------+-----+---------+------------------+
| Field | Type        | Null | Key | Default | Extra            |
+-------+-------------+------+-----+---------+------------------+
| doc   | json        | YES  |     | NULL    |                  |
| _id   | varchar(32) | NO   | PRI | NULL    | STORED GENERATED |
+-------+-------------+------+-----+---------+------------------+
2 rows in set (0.00 sec)

root@localhost [NEW57]> select * from X_JSON\G
*************************** 1. row ***************************
doc: {"id": 1, "_id": "26c8af795703e611630c0800279cea3c", "name": "Document Data", "price": 60000, "Conditions": ["NEW", 2016]}
_id: 26c8af795703e611630c0800279cea3c
1 row in set (0.00 sec)

root@localhost [NEW57]> 

【Beta Draft】
X DevAPI User Guide / Overview
http://dev.mysql.com/doc/x-devapi-userguide/en/devapi-users-introduction.html
その他、X DevAPI経由でコーディング出来そう。但し、現時点ではベータリリースなのでもう少ししたら確認。

【その他:Status変数】
こちらで、mysqlx経由の処理を確認する事が可能です。


[root@misc01 MID2016]# mysql -u root -p -e "show status like 'mysqlx%'"
Enter password: 
+-------------------------------------+--------------------------+
| Variable_name                       | Value                    |
+-------------------------------------+--------------------------+
| Mysqlx_bytes_received               | 389773                   |
| Mysqlx_bytes_sent                   | 3466                     |
| Mysqlx_connection_accept_errors     | 0                        |
| Mysqlx_connection_errors            | 0                        |
| Mysqlx_connections_accepted         | 2                        |
| Mysqlx_connections_closed           | 2                        |
| Mysqlx_connections_rejected         | 0                        |
| Mysqlx_crud_delete                  | 0                        |
| Mysqlx_crud_find                    | 0                        |
| Mysqlx_crud_insert                  | 0                        |
| Mysqlx_crud_update                  | 0                        |
| Mysqlx_errors_sent                  | 1                        |
| Mysqlx_expect_close                 | 0                        |
| Mysqlx_expect_open                  | 0                        |
| Mysqlx_init_error                   | 1                        |
| Mysqlx_notice_other_sent            | 76                       |
| Mysqlx_notice_warning_sent          | 2                        |
| Mysqlx_rows_sent                    | 18                       |
| Mysqlx_sessions                     | 0                        |
| Mysqlx_sessions_accepted            | 1                        |
| Mysqlx_sessions_closed              | 1                        |
| Mysqlx_sessions_fatal_error         | 0                        |
| Mysqlx_sessions_killed              | 0                        |
| Mysqlx_sessions_rejected            | 1                        |
| Mysqlx_ssl_accepts                  | 0                        |
| Mysqlx_ssl_active                   |                          |
| Mysqlx_ssl_cipher                   |                          |
| Mysqlx_ssl_cipher_list              |                          |
| Mysqlx_ssl_ctx_verify_depth         | 18446744073709551615     |
| Mysqlx_ssl_ctx_verify_mode          | 5                        |
| Mysqlx_ssl_finished_accepts         | 0                        |
| Mysqlx_ssl_server_not_after         | Oct 19 05:28:15 2025 GMT |
| Mysqlx_ssl_server_not_before        | Oct 22 05:28:15 2015 GMT |
| Mysqlx_ssl_verify_depth             |                          |
| Mysqlx_ssl_verify_mode              |                          |
| Mysqlx_ssl_version                  |                          |
| Mysqlx_stmt_create_collection       | 0                        |
| Mysqlx_stmt_create_collection_index | 0                        |
| Mysqlx_stmt_disable_notices         | 0                        |
| Mysqlx_stmt_drop_collection         | 0                        |
| Mysqlx_stmt_drop_collection_index   | 0                        |
| Mysqlx_stmt_enable_notices          | 0                        |
| Mysqlx_stmt_execute_sql             | 69                       |
| Mysqlx_stmt_execute_xplugin         | 2                        |
| Mysqlx_stmt_kill_client             | 0                        |
| Mysqlx_stmt_list_clients            | 0                        |
| Mysqlx_stmt_list_notices            | 0                        |
| Mysqlx_stmt_list_objects            | 2                        |
| Mysqlx_stmt_ping                    | 0                        |
| Mysqlx_worker_threads               | 2                        |
| Mysqlx_worker_threads_active        | 0                        |
+-------------------------------------+--------------------------+
[root@misc01 MID2016]# 

参考までに、MySQL ShellのSQLモードの場合とjavascriptモードの場合では接続が3306か33060からの接続かどうかは以下のステータス変数でも確認する事が可能です。

【SQLモードの場合】


[root@misc01 MID2016]# echo "INSERT INTO T_UC01 VALUES (1,'mysql shell'),(2,'マイエスキュウエルシェル');" | mysqlsh -u demo_user -ppassword --sql --schema=world_x2
mysqlx: [Warning] Using a password on the command line interface can be insecure.
[root@misc01 MID2016]# 


root@localhost [sys]> show status like 'Mysqlx_crud%';
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| Mysqlx_crud_delete | 0     |
| Mysqlx_crud_find   | 0     |
| Mysqlx_crud_insert | 0     |
| Mysqlx_crud_update | 0     |
+--------------------+-------+
4 rows in set (0.00 sec)

root@localhost [sys]> root@localhost [sys]> show status like 'Mysqlx_crud%';
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| Mysqlx_crud_delete | 0     |
| Mysqlx_crud_find   | 0     |
| Mysqlx_crud_insert | 0     |
| Mysqlx_crud_update | 0     |
+--------------------+-------+
4 rows in set (0.00 sec)

root@localhost [sys]> 


【JavaScriptモードの場合】


[root@misc01 MID2016]# mysqlsh --uri demo_user@localhost/NEW57 -ppassword
mysqlx: [Warning] Using a password on the command line interface can be insecure.
Creating an X Session to demo_user@localhost:33060/NEW57
Default schema `NEW57` accessible through db.

Welcome to MySQL Shell 1.0.3 Development Preview

Copyright (c) 2016, 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', '\h' or '\?' for help.

Currently in JavaScript mode. Use \sql to switch to SQL mode and execute queries.
mysql-js> db.createCollection("x_posts");
<Collection:x_posts>
mysql-js> db.x_posts.add({"title":"Hello World", "text":"This is the first post via mysqlx"});
Query OK, 1 item affected (0.01 sec)

mysql-js> db.x_posts.find("title = 'Hello World'").sort(["title"]);
[
    {
        "_id": "d2c6eb188b08e6113d110800279cea3c",
        "text": "This is the first post via mysqlx",
        "title": "Hello World"
    }
]
1 document in set (0.00 sec)

mysql-js> 

mysqlx経由のCRUDの実行数が確認出来る。
INSERT x 1回
SELECT x 1回


root@localhost [sys]> show status like 'Mysqlx_crud%';
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| Mysqlx_crud_delete | 0     |
| Mysqlx_crud_find   | 0     |
| Mysqlx_crud_insert | 0     |
| Mysqlx_crud_update | 0     |
+--------------------+-------+
4 rows in set (0.00 sec)

root@localhost [sys]> show status like 'Mysqlx_crud%';
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| Mysqlx_crud_delete | 0     |
| Mysqlx_crud_find   | 1     |
| Mysqlx_crud_insert | 1     |
| Mysqlx_crud_update | 0     |
+--------------------+-------+
4 rows in set (0.01 sec)

root@localhost [sys]> 


【参考】
http://dev.mysql.com/doc/refman/5.7/en/mysql-shell.html
http://dev.mysql.com/doc/refman/5.7/en/document-store.html
http://dev.mysql.com/doc/dev/connector-nodejs/
http://mysqlserverteam.com/mysql-5-7-12-part-3-more-than-just-sql/
http://mysqlserverteam.com/mysql-5-7-12-part-4-a-new-mysql-command-line-shell/

メモ:Node.jsのサンプルもあるので、後日、別途JSONドキュメント処理を実施してみる。
http://dev.mysql.com/doc/dev/connector-nodejs/


最近、MySQL5.7の形態素解析エンジンのmecabに関して辞書をカスタマイズ出来るかどうか
聞かれる事が増えた為、mecabの辞書をカスタマイズしてきちんと動作確認してみました。
結論としては、問題無くカスタマイズした辞書も利用出来るようです。
但し、MySQLのマニュアルページを見る限り、MySQL Binaryから提供されているmecab辞書の利用を推奨しているようです。

【以下、抜粋】
Installing MeCab From Source (Optional)
https://dev.mysql.com/doc/refman/5.7/en/fulltext-search-mecab.html
The mecab and mecab-ipadic packages distributed with the MySQL binary are recommended but
if you want to build mecab and mecab-ipadic from source, basic installation steps are provided below.
For additional information, refer to the MeCab documentation.

前回のmecab基本検証
http://variable.jp/2015/04/10/creating-index-with-utf8mb4-on-mecab-with-5-7-7/

基本的には、MySQLのmecab辞書は特に手を加えていないようです
MySQLのコンパイル済みTarからインストールした場合のファイル

 
[root@misc02 admin]# ls -l /usr/local/mysql/lib/mecab/dic/ipadic_utf-8
合計 51828
-rw-r--r--. 1 root mysql   262496 11月  6 23:18 char.bin
-rw-r--r--. 1 root mysql      693 11月  6 23:18 dicrc
-rw-r--r--. 1 root mysql    55910 11月  6 23:18 left-id.def
-rw-r--r--. 1 root mysql  3463716 11月  6 23:18 matrix.bin
-rw-r--r--. 1 root mysql     1477 11月  6 23:18 pos-id.def
-rw-r--r--. 1 root mysql     6241 11月  6 23:18 rewrite.def
-rw-r--r--. 1 root mysql    55910 11月  6 23:18 right-id.def
-rw-r--r--. 1 root mysql 49199027 11月  6 23:18 sys.dic
-rw-r--r--. 1 root mysql     5690 11月  6 23:18 unk.dic

MecabサイトからIPA辞書をダウンロードしてインストールした場合(手を加えていない場合)

[root@misc02 admin]# ls -l /usr/local/lib/mecab/dic/ipadic
合計 51828
-rw-r--r--. 1 root root   262496  4月  4 11:36 char.bin
-rw-r--r--. 1 root root      693  4月  4 11:36 dicrc
-rw-r--r--. 1 root root    55910  4月  4 11:36 left-id.def
-rw-r--r--. 1 root root  3463716  4月  4 11:36 matrix.bin
-rw-r--r--. 1 root root     1477  4月  4 11:36 pos-id.def
-rw-r--r--. 1 root root     6241  4月  4 11:36 rewrite.def
-rw-r--r--. 1 root root    55910  4月  4 11:36 right-id.def
-rw-r--r--. 1 root root 49199027  4月  4 11:36 sys.dic
-rw-r--r--. 1 root root     5690  4月  4 11:36 unk.dic
[root@misc02 admin]# 

ここから、実際に辞書を登録して新規ワードが追加された辞書を登録しています。
※ 事前にnkf等で辞書をUTF-8に変換していますが、ここでは説明を割愛してあります。

【辞書の追加】2つの名詞のみを登録
今回は、”日本オラクル株式会社”と”mecabプラグイン”の二つのみ登録して確認

[root@misc02 mecab]# cat user_defined_dictionary_utf8.csv 
日本オラクル株式会社,1285,1285,5078,名詞,一般,*,*,*,*,日本オラクル株式会社,ニホンオラクルカブシキガイシャ,ニホンオラクルカブシキガイシャ
mecabプラグイン,1285,1285,5699,名詞,一般,*,*,*,*,mecabプラグイン,メカブプラグイン,メカブプラグイン,和布蕪プラグイン
[root@misc02 mecab]# cp -rp user_defined_dictionary_utf8.csv mecab-ipadic-2.7.0-20070801/
[root@misc02 mecab]#

user_defined_dictionary_utf8.csvが作成した追加の辞書ファイル
2文字のみ登録しているので、2文字インデックシングされた事が以下のアウトプットから確認出来る。

[root@misc02 mecab-ipadic-2.7.0-20070801]# /usr/local/libexec/mecab/mecab-dict-index -f utf-8 -t utf-8
reading ./unk.def ... 40
emitting double-array: 100% |###########################################| 
./model.def is not found. skipped.
reading ./Adj.csv ... 27210
reading ./Adnominal.csv ... 135
reading ./Adverb.csv ... 3032
reading ./Auxil.csv ... 199
reading ./Conjunction.csv ... 171
reading ./Filler.csv ... 19
reading ./Interjection.csv ... 252
reading ./Noun.adjv.csv ... 3328
reading ./Noun.adverbal.csv ... 795
reading ./Noun.csv ... 60477
reading ./Noun.demonst.csv ... 120
reading ./Noun.nai.csv ... 42
reading ./Noun.name.csv ... 34202
reading ./Noun.number.csv ... 42
reading ./Noun.org.csv ... 16668
reading ./Noun.others.csv ... 151
reading ./Noun.place.csv ... 72999
reading ./Noun.proper.csv ... 27327
reading ./Noun.verbal.csv ... 12146
reading ./Others.csv ... 2
reading ./Postp-col.csv ... 91
reading ./Postp.csv ... 146
reading ./Prefix.csv ... 221
reading ./Suffix.csv ... 1393
reading ./Symbol.csv ... 208
reading ./Verb.csv ... 130750
reading ./user_defined_dictionary_utf8.csv ... 2
emitting double-array: 100% |###########################################| 
reading ./matrix.def ... 1316x1316
emitting matrix      : 100% |###########################################| 

done!
[root@misc02 mecab-ipadic-2.7.0-20070801]# make install
make[1]: ディレクトリ `/home/admin/mecab/mecab-ipadic-2.7.0-20070801' に入ります
make[1]: `install-exec-am' に対して行うべき事はありません.
/bin/sh ./mkinstalldirs /usr/local/lib/mecab/dic/ipadic
 /bin/install -c -m 644 ./matrix.bin /usr/local/lib/mecab/dic/ipadic/matrix.bin
 /bin/install -c -m 644 ./char.bin /usr/local/lib/mecab/dic/ipadic/char.bin
 /bin/install -c -m 644 ./sys.dic /usr/local/lib/mecab/dic/ipadic/sys.dic
 /bin/install -c -m 644 ./unk.dic /usr/local/lib/mecab/dic/ipadic/unk.dic
 /bin/install -c -m 644 ./left-id.def /usr/local/lib/mecab/dic/ipadic/left-id.def
 /bin/install -c -m 644 ./right-id.def /usr/local/lib/mecab/dic/ipadic/right-id.def
 /bin/install -c -m 644 ./rewrite.def /usr/local/lib/mecab/dic/ipadic/rewrite.def
 /bin/install -c -m 644 ./pos-id.def /usr/local/lib/mecab/dic/ipadic/pos-id.def
 /bin/install -c -m 644 ./dicrc /usr/local/lib/mecab/dic/ipadic/dicrc
make[1]: ディレクトリ `/home/admin/mecab/mecab-ipadic-2.7.0-20070801' から出ます
[root@misc02 mecab-ipadic-2.7.0-20070801]# 

mecab辞書を追加前
辞書追加前は、文字が分割されて辞書登録されている

[root@misc02 mecab-ipadic-2.7.0-20070801]# echo '日本オラクル株式会社' | /usr/local/bin/mecab
日本    名詞,固有名詞,地域,国,*,*,日本,ニッポン,ニッポン
オラクル        名詞,一般,*,*,*,*,*
株式会社        名詞,一般,*,*,*,*,株式会社,カブシキガイシャ,カブシキガイシャ
EOS
[root@misc02 mecab-ipadic-2.7.0-20070801]# 

[root@misc02 mecab-ipadic-2.7.0-20070801]# echo 'mecabプラグイン' | /usr/local/bin/mecab
mecab   名詞,固有名詞,組織,*,*,*,*
プラグ  名詞,一般,*,*,*,*,プラグ,プラグ,プラグ
イン    名詞,一般,*,*,*,*,イン,イン,イン
EOS
[root@misc02 mecab-ipadic-2.7.0-20070801]# 

mecab辞書を追加後
きちんと追加したWORDが1つの単語として認識されている事が分かる

[root@misc02 mecab]# echo '日本オラクル株式会社' | /usr/local/bin/mecab
日本オラクル株式会社    名詞,一般,*,*,*,*,日本オラクル株式会社,ニホンオラクルカブシキガイシャ,ニホンオラクルカブシキガイシャ
EOS
[root@misc02 mecab]# echo 'mecabプラグイン' | /usr/local/bin/mecab
mecabプラグイン 名詞,一般,*,*,*,*,mecabプラグイン,メカブプラグイン,メカブプラグイン,和布蕪プラグイン
EOS
[root@misc02 mecab]# 

検索対象文字列
Server1とServer2で同じデータを登録してIndexingしてあります。
また、mecab辞書はmy.cnfで新規作成したmecab辞書を参照するように設定済み。

root@localhost [mecab]> select description from articles where description like '%mecab%';
+-------------------------------------------------------------------------+
| description                                                             |
+-------------------------------------------------------------------------+
| MySQL mecabプラグインの辞書を追加した場合の動作確認                     |
| MySQL mecab                                                             |
+-------------------------------------------------------------------------+
2 rows in set (0.00 sec)

root@localhost [mecab]> select description from articles where description like '%日本%';
+---------------------------------------------------------------------------+
| description                                                               |
+---------------------------------------------------------------------------+
| 日本オラクル株式会社 辞書を追加した場合の動作確認                         |
| 日本オラクル                                                              |
+---------------------------------------------------------------------------+
2 rows in set (0.00 sec)

root@localhost [mecab]> 

オリジナルのmecab辞書
新規登録した単語では認識されていない。オリジナル辞書にあるmecabや日本と言った辞書で確認出来ている。

root@localhost [mecab]> OPTIMIZE TABLE articles;
+----------------+----------+----------+----------+
| Table          | Op       | Msg_type | Msg_text |
+----------------+----------+----------+----------+
| mecab.articles | optimize | status   | OK       |
+----------------+----------+----------+----------+
1 row in set (0.01 sec)

root@localhost [mecab]> SELECT word, doc_count, doc_id, position FROM information_schema.INNODB_FT_INDEX_TABLE where word like 'meca%';
+-------+-----------+--------+----------+
| word  | doc_count | doc_id | position |
+-------+-----------+--------+----------+
| mecab |         1 |     33 |        5 |
| mecab |         1 |     35 |        5 |
+-------+-----------+--------+----------+
2 rows in set (0.00 sec)

root@localhost [mecab]> SELECT word, doc_count, doc_id, position FROM information_schema.INNODB_FT_INDEX_TABLE where word like 'mecabプラグイン';
Empty set (0.01 sec)

root@localhost [mecab]> SELECT word, doc_count, doc_id, position FROM information_schema.INNODB_FT_INDEX_TABLE where word like '日本%';
+--------+-----------+--------+----------+
| word   | doc_count | doc_id | position |
+--------+-----------+--------+----------+
| 日本   |         1 |     34 |        0 |
| 日本   |         1 |     36 |        0 |
+--------+-----------+--------+----------+
2 rows in set (0.00 sec)

root@localhost [mecab]> SELECT word, doc_count, doc_id, position FROM information_schema.INNODB_FT_INDEX_TABLE where word like '日本オラクル%';
Empty set (0.01 sec)

root@localhost [mecab]> 
 

WORDを追加したmecab辞書
追加で単語が登録されているので、追加登録した辞書で文字列が検索出来ている。
サービスのニーズや流行りの言葉を登録させておく事により、ビジネスのニーズに柔軟に対応出来そうです。
大規模なサービスはSolr等の方が良いかもしれませんが、小規模~中規模のサービスには使えそうです。

root@localhost [mecab]> OPTIMIZE TABLE articles;
+----------------+----------+----------+----------+
| Table          | Op       | Msg_type | Msg_text |
+----------------+----------+----------+----------+
| mecab.articles | optimize | status   | OK       |
+----------------+----------+----------+----------+
1 row in set (0.01 sec)

root@localhost [mecab]>  SELECT word, doc_count, doc_id, position FROM information_schema.INNODB_FT_INDEX_TABLE where word like 'meca%';
+----------------------+-----------+--------+----------+
| word                 | doc_count | doc_id | position |
+----------------------+-----------+--------+----------+
| mecab                |         1 |     20 |        5 |
| mecabプラグイン      |         1 |     18 |        5 |
+----------------------+-----------+--------+----------+
2 rows in set (0.01 sec)

root@localhost [mecab]> SELECT word, doc_count, doc_id, position FROM information_schema.INNODB_FT_INDEX_TABLE where word like 'mecabプラグイン';
+----------------------+-----------+--------+----------+
| word                 | doc_count | doc_id | position |
+----------------------+-----------+--------+----------+
| mecabプラグイン      |         1 |     18 |        5 |
+----------------------+-----------+--------+----------+
1 row in set (0.00 sec)

root@localhost [mecab]> SELECT word, doc_count, doc_id, position FROM information_schema.INNODB_FT_INDEX_TABLE where word like '日本%';
+--------------------------------+-----------+--------+----------+
| word                           | doc_count | doc_id | position |
+--------------------------------+-----------+--------+----------+
| 日本                           |         1 |     21 |        0 |
| 日本オラクル株式会社           |         1 |     19 |        0 |
+--------------------------------+-----------+--------+----------+
2 rows in set (0.01 sec)

root@localhost [mecab]> SELECT word, doc_count, doc_id, position FROM information_schema.INNODB_FT_INDEX_TABLE where word like '日本オラクル%';
+--------------------------------+-----------+--------+----------+
| word                           | doc_count | doc_id | position |
+--------------------------------+-----------+--------+----------+
| 日本オラクル株式会社           |         1 |     19 |        0 |
+--------------------------------+-----------+--------+----------+
1 row in set (0.01 sec)

root@localhost [mecab]> 

search_output

参考:
12.9.9 MeCab Full-Text Parser Plugin
MeCab: Yet Another Part-of-Speech and Morphological Analyzer
単語の追加方法


MySQL5.7から追加されたGenerated Column(生成列)を使って、色々と便利な事が出来るようになりました。
先日、Generated Columnを利用してMySQLの照合順を説明したのでその時に利用した生成列をサンプル兼メモです。

Default: utf8_general_ci or utf8mb4_general_ciの場合
英語の大文字、小文字は同じ文字として扱う。


root@localhost [CONFIRM]> show create table T_Character\G
*************************** 1. row ***************************
       Table: T_Character
Create Table: CREATE TABLE `T_Character` (
  `pid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `string1` char(1) DEFAULT NULL,
  `string2` char(1) DEFAULT NULL,
  `string1_w_string` char(4) GENERATED ALWAYS AS (hex(weight_string(`string1`))) VIRTUAL,
  `string2_w_string` char(4) GENERATED ALWAYS AS (hex(weight_string(`string2`))) VIRTUAL,
  `compare` char(1) GENERATED ALWAYS AS ((`string1` = `string2`)) VIRTUAL,
  PRIMARY KEY (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4
1 row in set (0.01 sec)

root@localhost [CONFIRM]> select * from T_Character;
+-----+---------+---------+------------------+------------------+---------+
| pid | string1 | string2 | string1_w_string | string2_w_string | compare |
+-----+---------+---------+------------------+------------------+---------+
|   1 | A       | a       | 0041             | 0041             | 1       |
|   2 | あ      | ぁ      | 3042             | 3041             | 0       |
|   3 | か      | が      | 304B             | 304C             | 0       |
|   4 | あ      | ア      | 3042             | 30A2             | 0       |
|   5 | ア      | ア       | 30A2             | FF71             | 0       |
|   6 | は      | ぱ      | 306F             | 3071             | 0       |
|   7 | ハ      | パ      | 30CF             | 30D1             | 0       |
+-----+---------+---------+------------------+------------------+---------+
7 rows in set (0.00 sec)

root@localhost [CONFIRM]> 

Default: utf8_bin or utf8mb4_binの場合
英語の大文字、小文字は異なる文字として扱う。


root@localhost [CONFIRM]> show create table T_Character_COLLATE_utf8mb4_bin\G
*************************** 1. row ***************************
       Table: T_Character_COLLATE_utf8mb4_bin
Create Table: CREATE TABLE `T_Character_COLLATE_utf8mb4_bin` (
  `pid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `string1` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
  `string2` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
  `string1_w_string` char(8) GENERATED ALWAYS AS (hex(weight_string(`string1`))) VIRTUAL,
  `string2_w_string` char(8) GENERATED ALWAYS AS (hex(weight_string(`string2`))) VIRTUAL,
  `compare` char(1) GENERATED ALWAYS AS ((`string1` = `string2`)) VIRTUAL,
  PRIMARY KEY (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

root@localhost [CONFIRM]> select * from T_Character_COLLATE_utf8mb4_bin;
+-----+---------+---------+------------------+------------------+---------+
| pid | string1 | string2 | string1_w_string | string2_w_string | compare |
+-----+---------+---------+------------------+------------------+---------+
|   1 | A       | a       | 000041           | 000061           | 0       |
|   2 | あ      | ぁ      | 003042           | 003041           | 0       |
|   3 | か      | が      | 00304B           | 00304C           | 0       |
|   4 | あ      | ア      | 003042           | 0030A2           | 0       |
|   5 | ア      | ア       | 0030A2           | 00FF71           | 0       |
|   6 | は      | ぱ      | 00306F           | 003071           | 0       |
|   7 | ハ      | パ      | 0030CF           | 0030D1           | 0       |
+-----+---------+---------+------------------+------------------+---------+
7 rows in set (0.00 sec)

root@localhost [CONFIRM]> 

BIT型やINT型の変換等の確認にも利用可能


root@localhost [CONFIRM]> show create table T_BIT\G
*************************** 1. row ***************************
       Table: T_BIT
Create Table: CREATE TABLE `T_BIT` (
  `pid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `string1` bit(8) DEFAULT NULL,
  `string2` char(8) GENERATED ALWAYS AS ((`string1` + 0)) VIRTUAL,
  `string3_BIT` char(8) GENERATED ALWAYS AS (conv((`string1` + 0),10,2)) VIRTUAL,
  `string4_OCT` char(8) GENERATED ALWAYS AS (conv((`string1` + 0),10,8)) VIRTUAL,
  `string5_HEX` char(8) GENERATED ALWAYS AS (hex((`string1` + 0))) VIRTUAL,
  PRIMARY KEY (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

root@localhost [CONFIRM]> select * from T_BIT;
+-----+---------+---------+-------------+-------------+-------------+
| pid | string1 | string2 | string3_BIT | string4_OCT | string5_HEX |
+-----+---------+---------+-------------+-------------+-------------+
|   1 |        | 1       | 1           | 1           | 1           |
|   2 |        | 2       | 10          | 2           | 2           |
|   3 |        | 3       | 11          | 3           | 3           |
|   4 |        | 4       | 100         | 4           | 4           |
|   5 |        | 5       | 101         | 5           | 5           |
+-----+---------+---------+-------------+-------------+-------------+
5 rows in set (0.00 sec)

root@localhost [CONFIRM]> show create table T_BIGINT\G
*************************** 1. row ***************************
       Table: T_BIGINT
Create Table: CREATE TABLE `T_BIGINT` (
  `pid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `string1` bigint(64) DEFAULT NULL,
  `string2_2` char(8) GENERATED ALWAYS AS (conv(`string1`,10,2)) VIRTUAL,
  `string3_8` char(8) GENERATED ALWAYS AS (conv(`string1`,10,8)) VIRTUAL,
  `string2_16` char(8) GENERATED ALWAYS AS (conv(`string1`,10,16)) VIRTUAL,
  PRIMARY KEY (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

root@localhost [CONFIRM]> select * from T_BIGINT;
+-----+---------+-----------+-----------+------------+
| pid | string1 | string2_2 | string3_8 | string2_16 |
+-----+---------+-----------+-----------+------------+
|   1 |       1 | 1         | 1         | 1          |
|   2 |       2 | 10        | 2         | 2          |
|   3 |       3 | 11        | 3         | 3          |
|   4 |       4 | 100       | 4         | 4          |
|   5 |       5 | 101       | 5         | 5          |
|   6 |     255 | 11111111  | 377       | FF         |
|   7 |     100 | 1100100   | 144       | 64         |
+-----+---------+-----------+-----------+------------+
7 rows in set (0.00 sec)

root@localhost [CONFIRM]> 

色々と簡素化出来る事が出来るので、良く使う集計などは上記の様に、
GENERATED COLUMN(生成列)でまとめておくと楽かもしれません。

その他
生成列はJSONデータ型との相性が良いので、是非JSONデータ型と合わせて利用してみて下さい。
MySQLによるJSONデータ型処理
JSONデータとGenerated_Columnを使う場合の考慮事項


MySQL FabricにてSharding構成を組んだ環境において、MySQL Routerを利用する場合の設定確認。

Shardingされた環境においても、MySQL Fabric対応コネクターを利用するとアプリケーションからDBへの接続先はFabric管理サーバーで良い。
但し、MySQL Fabric対応コネクターを利用する為には既存アプリケーション書き換えなどが必要になり。導入が大変な為なかなか導入に踏み切れない。
MySQL Routerを利用するとアプリケーションの書き換えは殆ど必要無く、単純に接続先をMySQL Routerに向けるだけで済む為、導入が非常にシンプルになります。
データベースをMySQL FabricにてShardingしていない環境では、MySQL Routerの導入はアプリケーション側もインフラ側もハードルは高くない。
但し、MySQL FabricでShardingされている環境に対応させるには、MySQL Router設定ファイルにそれぞれのShardingグループ毎にMaster(Read-Write)とSlave(Read-Only)を追加する必要がある。
※ ここでは、MySQL Router2.0.2をベースに説明しています。

DB_Con_Shard

Fabricコネクターの場合(接続先はFabric管理ノード)
例)

import mysql.connector 
from mysql.connector import fabric
import time

省略 ...

       conn.set_property(tables=["test.employees"], key=str(emp_no), mode=fabric.MODE_READWRITE, scope=fabric.SCOPE_LOCAL)
省略 ...
       conn.set_property(tables=["test.employees"], key=str(emp_no), mode=fabric.MODE_READONLY, scope=fabric.SCOPE_LOCAL)
省略 ...
       conn=mysql.connector.connect(
          fabric={"host" : "localhost", "port" : 32274, "username": "admin", "password": "admin"}, user="app", database="test", password="app", autocommit=True

MySQL Routerの場合

Router設定ファイルに関してのマニュアル
● Fabricを利用しない場合のRouter設定 (Routerのみの利用の場合)
必要に応じて、connect_timeoutやmax_connectionsを調整して下さい。
https://dev.mysql.com/doc/mysql-router/en/mysql-router-configuration-setup-connection-routing.html

● FabricとRouterを連携する場合のRouter設定
https://dev.mysql.com/doc/mysql-router/en/mysql-router-plugins-fabric-cache.html

MySQL Routerの接続定義ファイルに、以下のようにそれぞれのSharding Groupに対しての接続を作成する。
面倒ですが、アプリケーションからはCaseやIfなどによってSharding Keyの値によって接続先を適宜切り替える必要がある。

以下のような環境の場合の設定

-bash-4.2$ mysqlfabric dump sharding_information
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1
schema_name table_name column_name lower_bound shard_id type_name group_id global_group
----------- ---------- ----------- ----------- -------- --------- -------- ------------
       test  employees      emp_no           1        1     RANGE   shard1       global
       test  employees      emp_no         500        2     RANGE   shard2       global


sharding_def

上記のような環境では、MySQLFabricの定義ファイルは以下のように設定

[fabric_cache:ha1]
address = localhost:32275
user = admin

[routing:Read_Write_Global]
bind_port = 7001
destinations = fabric+cache://ha1/group/global
mode = read-write

[routing:Read_Only_Global]
bind_port = 7002 
destinations = fabric+cache://ha1/group/global
mode = read-only

[routing:Read_Write_shard1]
bind_port = 7003
destinations = fabric+cache://ha1/group/shard1
mode = read-write

[routing:Read_Only_shard1]
bind_port = 7004
destinations = fabric+cache://ha1/group/shard1
mode = read-only

[routing:Read_Write_shard2]
bind_port = 7005
destinations = fabric+cache://ha1/group/shard2
mode = read-write

[routing:Read_Only_shard2]
bind_port = 7006
destinations = fabric+cache://ha1/group/shard2
mode = read-only
[keepalive]
interval = 60

例えば、Shardingグループshard1に対して、書き込みする場合は以下のようにMySQL RouterのRead-Writeに対して接続し、読み込む場合は、shard1のRead-Onlyに対して接続します。書き込みは通常のRouterの動作として、マスター障害が発生するまでは、同じサーバーにアクセスします。読み込みは、以下のようにアクセスする度にラウンドロビンで異なるサーバーに接続されます。


-bash-4.2$ mysql -h 127.0.0.1 -P 7004 -u root --password=root -e "select count(*),@@port FROM test.employees"
+----------+--------+
| count(*) | @@port |
+----------+--------+
|       22 |  63305 |
+----------+--------+

-bash-4.2$ mysql -h 127.0.0.1 -P 7003 -u root --password=root -e "insert into test.employees(emp_no,first_name,last_name) values(23,'Shard1','Insert from P7003')"

-bash-4.2$ mysql -h 127.0.0.1 -P 7004 -u root --password=root -e "select count(*),@@port FROM test.employees"
+----------+--------+
| count(*) | @@port |
+----------+--------+
|       23 |  63304 |
+----------+--------+

-bash-4.2$ mysql -h 127.0.0.1 -P 7004 -u root --password=root -e "select count(*),@@port FROM test.employees"
+----------+--------+
| count(*) | @@port |
+----------+--------+
|       23 |  63305 |
+----------+--------+

MySQL Routerは2015年にリリースされたばかりですが、要件定義と事前検証をしっかり行い利用する事で、
サイト運用者の負荷を軽減する事が可能かと思います。また、システム開発する上での、システムデザインの幅も広げる事が可能です。

Routerを導入したり、その他サポートを受けて自社の工数を削減して生産性を上げたい場合はEnterprise Editionを検討すると良いかと思います。
https://www-jp.mysql.com/products/

その他、もっとシンプルにShardingを導入したい場合はMySQL Clusterを検討しても良いかと思います。
データを各データノードに分散するので、PKベースの処理が殆どの割合を占める場合には良い選択肢かと思います。
以下のページが参考になるかと思います。

奥野氏
MySQL Cluster 7.4で楽しむスケールアウト
山崎氏
MySQL Clusterの特徴とアーキテクチャ
@RDBMS
MySQL ClusterによるNoSQL処理(ClusterJ)

その他、関連メモ
MySQL RouterとMySQL Fabric連携による可用性の向上
MySQL Fabricにおけるsharding Table定義の変更
mysqlfabric shardingで分割したデータの読み込み