Quantcast
Channel: Planet MySQL
Viewing all articles
Browse latest Browse all 1081

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

$
0
0

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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


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

json_extractでJSONデータを参照

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

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

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

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

参照: 8.3.9 Optimizer Use of Generated Column Indexes


PlanetMySQL Voting: Vote UP / Vote DOWN

Viewing all articles
Browse latest Browse all 1081

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>