第260回 MySQL 9.
ただし、MySQLでは一部機能がEnterprise Edition限定で提供されるとも記載されています。ではCommunity Editionではどこまで使えるのでしょうか。そこで今回は、MySQL 9.
- 作成できるのか
- 参照できるのか
- 更新できるのか
- 実行計画はどうなるのか
_metadata.はどのように振る舞うのかetag
を一通り検証してみました。
最初に、検証の事前準備として以下のテーブルを作成して、データを入れておきます。
CREATE TABLE authors (
author_id INT PRIMARY KEY,
display_name VARCHAR(100) NOT NULL
);
CREATE TABLE posts (
post_id INT PRIMARY KEY,
author_id INT NOT NULL,
title VARCHAR(255) NOT NULL,
published_at DATETIME NULL,
CONSTRAINT fk_posts_authors
FOREIGN KEY (author_id) REFERENCES authors(author_id)
);
CREATE TABLE comments (
comment_id INT PRIMARY KEY,
post_id INT NOT NULL,
commenter VARCHAR(100) NOT NULL,
body VARCHAR(500) NOT NULL,
created_at DATETIME NOT NULL,
CONSTRAINT fk_comments_posts
FOREIGN KEY (post_id) REFERENCES posts(post_id)
);
INSERT INTO authors VALUES
(1, 'Fukamachi'), (2, 'Kimura'), (3, 'Kitagawa');
INSERT INTO posts VALUES
(10, 1, 'MySQLアップグレードで顕在化したINTと空文字のバグ挙動', '2026-02-25 20:00:00'),
(11, 1, 'MySQL9.4に追加されたJSON Duality Viewってなに?', '2026-02-26 21:00:00'),
(20, 2, '知ってるとちょっと便利なON UPDATE CURRENT_TIMESTAMP', '2026-02-27 19:00:00'),
(30, 3, 'MySQL 9.4と9.5の新機能について', '2026-02-27 19:00:00');
INSERT INTO comments VALUES
(100, 11, 'kim', 'Communityでどこまで動くかが知りたい', '2026-02-26 21:10:00'),
(101, 11, 'fuk', 'こんな機能あったんだ。', '2026-02-26 21:12:00'),
(200, 10, 'kim', 'こんなbugあったんだ', '2026-02-25 20:10:00'),
(300, 20, 'kita', 'まとめ助かる', '2026-02-27 19:10:00');
JSON Duality Viewとは何者か
JSON Duality Viewは、複数のリレーショナルテーブルを1つのJSONドキュメントとして定義するビューです。定義にはJSON_という専用の構文を使います。
ここでまず気付くのは、この関数が通常のJSON関数とは性質が異なる点です。JSON_などとは違い、通常のSELECTでそのまま利用することはできません。下記のようにSQLを実行するとエラーになります。
mysql> SELECT JSON_DUALITY_OBJECT('_id': 1);
ERROR 6484 (HY000): JSON_DUALITY_OBJECT() can only be used to define a JSON duality view.
JSON_は、JSONを生成するための関数というよりも、JSON Duality Viewの構造を宣言するための専用構文に近い存在のようです。
たとえば、以下のようにJSON Duality Viewの定義内で利用します。
mysql> CREATE OR REPLACE JSON RELATIONAL DUALITY VIEW author_posts_dv AS
-> SELECT JSON_DUALITY_OBJECT(
-> '_id': author_id,
-> 'display_name': display_name,
-> 'posts': (
-> SELECT JSON_ARRAYAGG(
-> JSON_DUALITY_OBJECT(
-> 'post_id': post_id,
-> 'title': title,
-> 'published_at': published_at
-> )
-> )
-> FROM posts
-> WHERE posts.author_id = authors.author_id
-> )
-> )
-> FROM authors;
Query OK, 0 rows affected (0.006 sec)
mysql> CREATE OR REPLACE JSON RELATIONAL DUALITY VIEW post_detail_dv AS
-> SELECT JSON_DUALITY_OBJECT(WITH(INSERT,UPDATE,DELETE)
-> '_id': post_id,
-> 'title': title,
-> 'published_at': published_at,
->
-> 'author': (
-> SELECT JSON_DUALITY_OBJECT(
-> 'author_id': author_id,
-> 'display_name': display_name
-> )
-> FROM authors
-> WHERE authors.author_id = posts.author_id
-> ),
-> 'comments': (
-> SELECT JSON_ARRAYAGG(
-> JSON_DUALITY_OBJECT(
-> 'comment_id': comment_id,
-> 'commenter': commenter,
-> 'body': body,
-> 'created_at': created_at
-> )
-> )
-> FROM comments
-> WHERE comments.post_id = posts.post_id
-> )
-> )
-> FROM posts;
Query OK, 0 rows affected (0.008 sec)
Community Editionでも作成・参照は可能
まず結論から言うと、前述のクエリが実行できるように、Community EditionでもJSON Duality Viewの作成は問題なく実行できます。
先ほど作成したJSON Duality Viewがどのような出力を返すのか、確認してみましょう
# mysql -uroot -p**** -sse "SELECT * FROM post_detail_dv LIMIT 1" dv_test | jq
{
"_id": 10,
"title": "MySQLアップグレードで顕在化したINTと空文字のバグ挙動",
"author": {
"author_id": 1,
"display_name": "Fukamachi"
},
"comments": [
{
"body": "こんなbugあったんだ",
"commenter": "kim",
"comment_id": 200,
"created_at": "2026-02-25 20:10:00.000000"
}
],
"_metadata": {
"etag": "b739e056dbe74a9c622c6ae49c624c77"
},
"published_at": "2026-02-25 20:00:00.000000"
}
ここで目を引くのが_metadata.の存在です。
通常のVIEW + JSON_ではこのようなメタ情報は付きません。JSON Duality Viewは単にJSONを返すだけでなく、JSON Duality Viewの結果として自動的に付与されているように見えます。
少なくとも
DML は Enterprise Edition限定
では、JSON経由での更新はどうでしょうか。以下のようにJSON Duality Viewに対してUPDATEを実行してみます。
mysql> UPDATE post_detail_dv
-> SET data = JSON_SET(
-> data,
-> '$.title',
-> '(修正版)MySQL9.4に追加されたJSON Duality Viewってなに?'
-> )
-> WHERE data->'$._id' = 11;
ERROR 6503 (HY000): Feature not available in this edition.
「このエディションでは利用できない」ERROR 6503となります。
興味深い点は、Community EditionでJSON Duality Viewの定義時にテーブルアノテーションとしてWITH(INSERT,UPDATE,DELETE)を指定しても、作成自体は成功する点です。
WITH (INSERT,UPDATE,DELETE)が確認できるmysql> show create view post_detail_dv\G
*************************** 1. row ***************************
View: post_detail_dv
Create View: CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER JSON RELATIONAL DUALITY VIEW `post_detail_dv` AS select json_duality_object( WITH (INSERT,UPDATE,DELETE) '_id':`posts`.`post_id`,'title':`posts`.`title`,'published_at':`posts`.`published_at`,'author':(select json_duality_object('author_id':`authors`.`author_id`,'display_name':`authors`.`display_name`) from `authors` where (`authors`.`author_id` = `posts`.`author_id`)),'comments':(select json_arrayagg(json_duality_object('comment_id':`comments`.`comment_id`,'commenter':`comments`.`commenter`,'body':`comments`.`body`,'created_at':`comments`.`created_at`)) from `comments` where (`comments`.`post_id` = `posts`.`post_id`))) AS `Name_exp_1` from `posts`
character_set_client: utf8mb4
collation_connection: utf8mb4_0900_ai_ci
1 row in set (0.001 sec)
つまり今回の検証では、
- 構文はエディションに関係なく定義できる
- ただしJSON経由のDML実行時にエディション差で制御される
という挙動になっているように見えました。少なくともCommunity Editionでは、JSON経由DMLは明確にEnterprise Editionの機能として切り分けられているようです。
_metadata.etag はどう変わるのか
JSON Duality Viewの特徴のひとつが_metadata.です。etagの変化の粒度も確認してみましょう。
親テーブル更新
まずは親テーブルの値の更新です。
下記のように authors.を変更するとetagの値が変更されています。つまり、親テーブルの値の変更によりetagの値が変更されていることが確認できます。
mysql> SELECT
-> data->>'$._id' AS _id,
-> data->>'$.display_name' AS display_name,
-> data->>'$._metadata.etag' AS etag
-> FROM author_posts_dv
-> WHERE data->'$._id' = 1;
+------+--------------+----------------------------------+
| _id | display_name | etag |
+------+--------------+----------------------------------+
| 1 | Fukamachi | 51243a50cc232f77f498a4a63f2eb618 |
+------+--------------+----------------------------------+
1 row in set (0.001 sec)
mysql> UPDATE authors
-> SET display_name = CONCAT(display_name, '_v2')
-> WHERE author_id = 1;
Query OK, 1 row affected (0.004 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> SELECT
-> data->>'$._id' AS _id,
-> data->>'$.display_name' AS display_name,
-> data->>'$._metadata.etag' AS etag
-> FROM author_posts_dv
-> WHERE data->'$._id' = 1;
+------+--------------+----------------------------------+
| _id | display_name | etag |
+------+--------------+----------------------------------+
| 1 | Fukamachi_v2 | 6739b2c2bd52d66e4e4c201624c4d1c4 |
+------+--------------+----------------------------------+
1 row in set (0.001 sec)
子テーブル更新
小テーブルも同様にposts.
mysql> SELECT
-> data->>'$._id' AS _id,
-> data->>'$._metadata.etag' AS etag
-> FROM author_posts_dv
-> WHERE data->'$._id' = 1;
+------+----------------------------------+
| _id | etag |
+------+----------------------------------+
| 1 | 6739b2c2bd52d66e4e4c201624c4d1c4 |
+------+----------------------------------+
1 row in set (0.002 sec)
mysql>
mysql> UPDATE posts
-> SET title = CONCAT(title, '(追記)')
-> WHERE post_id = 11;
Query OK, 1 row affected (0.003 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> SELECT
-> data->>'$._id' AS _id,
-> data->>'$._metadata.etag' AS etag
-> FROM author_posts_dv
-> WHERE data->'$._id' = 1;
+------+----------------------------------+
| _id | etag |
+------+----------------------------------+
| 1 | d8cd09f82c51c3cb496181b20feda5a3 |
+------+----------------------------------+
1 row in set (0.001 sec)
同値 UPDATE(Changed: 0)
では同値でUPDATEを行った場合はどうなるでしょうか。同値でUPDATEした場合、
mysql> SELECT
-> data->>'$._id' AS _id,
-> data->>'$.display_name' AS display_name,
-> data->>'$._metadata.etag' AS etag
-> FROM author_posts_dv
-> WHERE data->'$._id' = 1;
+------+--------------+----------------------------------+
| _id | display_name | etag |
+------+--------------+----------------------------------+
| 1 | Fukamachi_v2 | d8cd09f82c51c3cb496181b20feda5a3 |
+------+--------------+----------------------------------+
1 row in set (0.001 sec)
mysql> UPDATE authors SET display_name = 'Fukamachi_v2' WHERE author_id = 1;
Query OK, 0 rows affected (0.001 sec)
Rows matched: 1 Changed: 0 Warnings: 0
mysql> SELECT
-> data->>'$._id' AS _id,
-> data->>'$.display_name' AS display_name,
-> data->>'$._metadata.etag' AS etag
-> FROM author_posts_dv
-> WHERE data->'$._id' = 1;
+------+--------------+----------------------------------+
| _id | display_name | etag |
+------+--------------+----------------------------------+
| 1 | Fukamachi_v2 | d8cd09f82c51c3cb496181b20feda5a3 |
+------+--------------+----------------------------------+
1 row in set (0.001 sec)
どうやらetagは
JSON Duality Viewの実行計画を見てみる
例として以下の実行計画を取得してみてみましょう。
mysql> EXPLAIN FORMAT=TREE SELECT data FROM post_detail_dv WHERE data->'$._id' = 11\G
*************************** 1. row ***************************
EXPLAIN: -> Filter: (json_extract(post_detail_dv.`data`,'$._id') = 11) (cost=2.95 rows=4)
-> Table scan on post_detail_dv (cost=2.21..4.12 rows=4)
-> Materialize (cost=1.57..1.57 rows=4)
-> Table scan on posts (cost=0.65 rows=4)
-> Select #4 (subquery in projection; dependent)
-> Single-row index lookup on authors using PRIMARY (author_id = posts.author_id) (cost=0.35 rows=1)
-> Select #3 (subquery in projection; dependent)
-> Aggregate: json_arrayagg(json_duality_object('comment_id':comments.comment_id,'commenter':comments.commenter,'body':comments.body,'created_at':comments.created_at)) (cost=0.774 rows=1)
-> Index lookup on comments using fk_comments_posts (post_id = posts.post_id) (cost=0.467 rows=1.33)
1 row in set, 2 warnings (0.001 sec)
今回の結果を見る限り、data->'$._id' = 11という条件はposts.に単純に書き換えられるのではなく、json_によるフィルタとして評価されているように見えました。さらに、ビュー全体がいったん Materializeされた後、その結果に対してフィルタが適用される形になっています。一方で、ネスト先のauthorsやcommentsについてはインデックスが利用されていました。
小規模なデータでは大きな問題になりませんが、Duality Viewを検索の中心に据える場合は、一度EXPLAINを確認しておくのがよさそうです。
まとめ
ここまで検証してみた結果、Community EditionにおけるJSON Duality Viewの位置づけは、次のように整理できそうです。
- JSON Duality View自体の作成は可能
- JSONドキュメントとして参照できる
- _metadata.
etagによる変更検知用のメタ情報を持つ - ルート・
子テーブルの更新に応じてetagは変化する - ただしJSON経由のDML
(INSERT / UPDATE / DELETE) はEnterprise Edition限定
子テーブルの更新でもetagが変化することから、JSON Duality Viewは単にJSONを生成しているだけでなく、ルート単位のひとつのドキュメントとして扱われていることがうかがえます。一方で、実行計画を見る限り、JSONパス条件がそのままjson_
Community EditionではDMLが利用できないため、現実的には