まず自分自身がMariaDBの生成カラム周りおよびJSONについて、
以下2点勘違いをしていた。
- MariaDBでもMySQLと同様に、VIRTUAL COLUMNにインデックスを張ることができる(すいません、できないと思ってました。。)
- MariaDBでもCHECK制約を使うことで、「JSONの正しさ」を保証できる(すいません、できないと思ってました。。)
以前書いた記事にも訂正を追記しておきました。
というわけで、MariaDB10.2.17、10.3.10のバージョンで生成カラムについて見ていきます。
ではまず、以下のようなテーブルを作ってみます。
CREATE TABLE `mail` ( `id` int(10) NOT NULL AUTO_INCREMENT, `to` varchar(255) NOT NULL, `cc` varchar(255), `bcc` varchar(255), `subject` varchar(255) NOT NULL, `body` json NOT NULL, `addrs` text AS (CONCAT_WS(',', `to`, `cc`, `bcc`)) PERSISTENT, `sign` varchar(255) AS (JSON_VALUE(`body`, '$.sign')) VIRTUAL, CHECK (JSON_VALID(`body`)), PRIMARY KEY (`id`), FULLTEXT KEY `mail_fidx01` (`addrs`), KEY `mail_idx01` (`sign`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
ちょっと長いのですが、ポイントは以下の通り。
- addrsカラムに対して、PERSISTENTタイプの生成カラムを利用して、全文検索INDEXを張る
- bodyカラムに対して、JSONの型チェックを行う
- signカラムに対して、VIRTUALタイプの生成カラムを利用して、JSONの部分抽出を行い、セカンダリーINDEXを張る
1はカラムを結合した状態を全文検索にしたい場合、
2はJSONの正しさを保証したい場合、
3はJSONの中の特定のキーを条件に高速にデータアクセスしたい場合、
に用いられるような想定です。
この状態のテーブルを見てみます。
MariaDB [test]> desc mail; +---------+--------------+------+-----+---------+-------------------+ | Field | Type | Null | Key | Default | Extra | +---------+--------------+------+-----+---------+-------------------+ | id | int(10) | NO | PRI | NULL | auto_increment | | to | varchar(255) | NO | | NULL | | | cc | varchar(255) | YES | | NULL | | | bcc | varchar(255) | YES | | NULL | | | subject | varchar(255) | NO | | NULL | | | body | longtext | NO | | NULL | | | addrs | text | YES | MUL | NULL | STORED GENERATED | | sign | varchar(255) | YES | MUL | NULL | VIRTUAL GENERATED | +---------+--------------+------+-----+---------+-------------------+ 8 rows in set (0.002 sec) MariaDB [test]> show index from mail; +-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | mail | 0 | PRIMARY | 1 | id | A | 0 | NULL | NULL | | BTREE | | | | mail | 1 | mail_idx01 | 1 | sign | A | 0 | NULL | NULL | YES | BTREE | | | | mail | 1 | mail_fidx01 | 1 | addrs | NULL | NULL | NULL | NULL | YES | FULLTEXT | | | +-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 3 rows in set (0.000 sec)
生成カラムの情報がdescのExtraにも表現されていますね。
ちなみに、生成カラムは「NOT NULL DEFAULT ・・・」は付けられないようで、生成カラムの評価ができない(失敗?)の場合は、NULLが入る仕様のようです。
次に以下のようなデータを流し込んで、結果を見てみます。
INSERT INTO `mail` (`to`, `cc`, `bcc`, `subject`, `body`) VALUES ('to-00001@example.com', 'cc-00001@example.com', 'bcc-00001@example.com', 'subject-00001', '{"sign": "sign-00001", "message": "message-00001"}'); INSERT INTO `mail` (`to`, `cc`, `bcc`, `subject`, `body`) VALUES ('to-00002@example.com', 'cc-00002@example.com', null , 'subject-00002', '{"sign": "sign-00002", "message": "message-00002"}'); INSERT INTO `mail` (`to`, `cc`, `bcc`, `subject`, `body`) VALUES ('to-00003@example.com', null , null , 'subject-00003', '{"sign": "sign-00003", "message": "message-00003"}'); INSERT INTO `mail` (`to`, `cc`, `bcc`, `subject`, `body`) VALUES ('to-00004@example.com', null , null , 'subject-00004', '{"message": "message-00004"}');
MariaDB [test]> select * from mail\G; *************************** 1. row *************************** id: 1 to: to-00001@example.com cc: cc-00001@example.com bcc: bcc-00001@example.com subject: subject-00001 body: {"sign": "sign-00001", "message": "message-00001"} addrs: to-00001@example.com,cc-00001@example.com,bcc-00001@example.com sign: sign-00001 *************************** 2. row *************************** id: 2 to: to-00002@example.com cc: cc-00002@example.com bcc: NULL subject: subject-00002 body: {"sign": "sign-00002", "message": "message-00002"} addrs: to-00002@example.com,cc-00002@example.com sign: sign-00002 *************************** 3. row *************************** id: 3 to: to-00003@example.com cc: NULL bcc: NULL subject: subject-00003 body: {"sign": "sign-00003", "message": "message-00003"} addrs: to-00003@example.com sign: sign-00003 *************************** 4. row *************************** id: 4 to: to-00004@example.com cc: NULL bcc: NULL subject: subject-00004 body: {"message": "message-00004"} addrs: to-00004@example.com sign: NULL 4 rows in set (0.000 sec)
ちゃんとデータが入っていますので、
PERSISTENTタイプのaddrsへの全文検索と、
VIRTUALタイプのsignへの検索を行ってみます。
・PERSISTENTタイプのaddrsへの全文検索
MariaDB [test]> select * from mail where match(addrs) against('cc-00002')\G; *************************** 1. row *************************** id: 2 to: to-00002@example.com cc: cc-00002@example.com bcc: NULL subject: subject-00002 body: {"sign": "sign-00002", "message": "message-00002"} addrs: to-00002@example.com,cc-00002@example.com sign: NULL 1 row in set (0.001 sec) MariaDB [test]> explain select * from mail where match(addrs) against('cc-00002')\G; *************************** 1. row *************************** id: 1 select_type: SIMPLE table: mail type: fulltext possible_keys: mail_fidx01 key: mail_fidx01 key_len: 0 ref: rows: 1 Extra: Using where 1 row in set (0.000 sec)
・VIRTUALタイプのsignへの検索
MariaDB [test]> select * from mail where sign = 'sign-00003'\G; *************************** 1. row *************************** id: 3 to: to-00003@example.com cc: NULL bcc: NULL subject: subject-00003 body: {"sign": "sign-00003", "message": "message-00003"} addrs: to-00003@example.com sign: sign-00003 1 row in set (0.001 sec) MariaDB [test]> explain select * from mail where sign = 'sign-00003'\G; *************************** 1. row *************************** id: 1 select_type: SIMPLE table: mail type: ref possible_keys: mail_idx01 key: mail_idx01 key_len: 1023 ref: const rows: 1 Extra: Using where 1 row in set (0.001 sec)
ちょっと件数少ないですが、両方共INDEXが効いていることがわかります。
生成カラムって実際どのくらい使われているのかわかりませんが、うまく使うことで、機能追加にも柔軟な対応ができそうな予感です。
生成カラムの進化はこれからも期待しています。
おっと、INSTANT ADDは、生成カラムには効かないので、ご注意ください。INSTANT対応も今後はあるのでは、と期待してます。
以上
コメントがあればどうぞ