
{"id":1533,"date":"2015-11-17T16:21:29","date_gmt":"2015-11-17T15:21:29","guid":{"rendered":"http:\/\/dasini.net\/blog\/?p=1533"},"modified":"2024-12-10T15:46:23","modified_gmt":"2024-12-10T14:46:23","slug":"30-mins-avec-json-en-mysql","status":"publish","type":"post","link":"https:\/\/dasini.net\/blog\/2015\/11\/17\/30-mins-avec-json-en-mysql\/","title":{"rendered":"30 mins avec JSON en MySQL"},"content":{"rendered":"<p><em><a href=\"http:\/\/dasini.net\/blog\/2015\/11\/17\/30-mins-with-json-in-mysql\/\">Read this post in English<\/a><\/em><\/p>\n<p><em><span style=\"text-decoration: underline;\">Note<\/span>: Cet article est inspir\u00e9 de la pr\u00e9sentation\u00a0<a href=\"http:\/\/www.slideshare.net\/morgo\/mysql-57-json\" target=\"_blank\" rel=\"noopener noreferrer\">MySQL 5.7 + JSON<\/a> de\u00a0<a href=\"http:\/\/www.tocker.ca\/\" target=\"_blank\" rel=\"noopener noreferrer\">Morgan Tocker<\/a>.<\/em><\/p>\n<p><em><span style=\"text-decoration: underline;\">Note<\/span> 2: L&rsquo;article suivant peut t\u2019int\u00e9resser \u00e9galement:\u00a0<a href=\"http:\/\/dasini.net\/blog\/2018\/07\/23\/30-mins-avec-les-fonctions-json-de-mysql\/\" target=\"_blank\" rel=\"noopener noreferrer\">30 mins avec les fonctions JSON de MySQL<\/a>.<\/em><\/p>\n<p><span style=\"text-decoration: underline;\"><em>Note<\/em><\/span> 3: Tu peux \u00e9galement manipuler tes documents JSON avec <a href=\"http:\/\/dasini.net\/blog\/2019\/04\/02\/mysql-json-document-store\/\" target=\"_blank\" rel=\"noopener noreferrer\">MySQL Document Store<\/a>.<\/p>\n<p>Comme vous le savez <a href=\"http:\/\/dev.mysql.com\/downloads\/mysql\/5.7.html\" target=\"_blank\" rel=\"noopener noreferrer\">MySQL 5.7<\/a> est <a href=\"https:\/\/www.oracle.com\/corporate\/pressrelease\/mysql-5-7-ga-101915.html\" target=\"_blank\" rel=\"noopener noreferrer\">GA<\/a>. Cette nouvelle mouture de la base de donn\u00e9es open source la plus populaire au monde a plus de <a href=\"http:\/\/www.thecompletelistoffeatures.com\/\" target=\"_blank\" rel=\"noopener noreferrer\">150 nouvelles fonctionnalit\u00e9s<\/a>. L&rsquo;une d&rsquo;entre elle est<b> un type de donn\u00e9es JSON natif ainsi que les fonctions JSON associ\u00e9es<\/b>.<\/p>\n<p>Prenons 30 minutes pour voir ce que cela donne&#8230;<\/p>\n<h1>R\u00e9cup\u00e9rer des documents JSON<\/h1>\n<p>Commen\u00e7ons pas r\u00e9cup\u00e9rer des donn\u00e9es au format JSON. <a href=\"https:\/\/github.com\/zemirco\" target=\"_blank\" rel=\"noopener noreferrer\">Mirco Zeiss<\/a> fournit un gros fichier JSON qui repr\u00e9sente San Francisco (<a href=\"https:\/\/data.sfgov.org\/\" target=\"_blank\" rel=\"noopener noreferrer\">SF Open Data<\/a>) : <a href=\"https:\/\/github.com\/zemirco\/sf-city-lots-json\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/github.com\/zemirco\/sf-city-lots-json<\/a><\/p>\n<p>Pour pouvoir manipuler ces donn\u00e9es avec MySQL, quelques modifications sont n\u00e9cessaires:<\/p>\n<pre class=\"lang:sh decode:true\">$ grep \"^{ \\\"type\" citylots.json &gt; properties.json\n\n$ head -n1 properties.json \n{  \n   \"type\":\"Feature\",\n   \"properties\":{  \n      \"MAPBLKLOT\":\"0001001\",\n      \"BLKLOT\":\"0001001\",\n      \"BLOCK_NUM\":\"0001\",\n      \"LOT_NUM\":\"001\",\n      \"FROM_ST\":\"0\",\n      \"TO_ST\":\"0\",\n      \"STREET\":\"UNKNOWN\",\n      \"ST_TYPE\":null,\n      \"ODD_EVEN\":\"E\"\n   },\n   \"geometry\":{  \n      \"type\":\"Polygon\",\n      \"coordinates\":[  \n         [  \n            [  \n               -122.422003528252475,\n               37.808480096967251,\n               0.0\n            ],\n            [  \n               -122.422076013325281,\n               37.808835019815085,\n               0.0\n            ],\n            [  \n               -122.421102174348633,\n               37.808803534992904,\n               0.0\n            ],\n            [  \n               -122.421062569067274,\n               37.808601056818148,\n               0.0\n            ],\n            [  \n               -122.422003528252475,\n               37.808480096967251,\n               0.0\n            ]\n         ]\n      ]\n   }\n}<\/pre>\n<p>\u00c7a \u00e0 l&rsquo;air bon !<\/p>\n<p>Note: <em>La taille des documents\u00a0JSON stock\u00e9s dans une colonne de type JSON est limit\u00e9e par la valeur de la variable syst\u00e8me <a href=\"http:\/\/dev.mysql.com\/doc\/refman\/5.7\/en\/server-system-variables.html#sysvar_max_allowed_packet\" target=\"_blank\" rel=\"noopener noreferrer\">max_allowed_packet<\/a>. (Cette limitation ne s&rsquo;applique que lorsque le serveur stocke les documents. En m\u00e9moire la taille des document peut donc \u00eatre sup\u00e9rieure).<br \/>\n<\/em><\/p>\n<p>Notre document JSON sera stock\u00e9 dans la table InnoDB <i>features<\/i>:<\/p>\n<pre class=\"lang:mysql decode:true\">CREATE TABLE features (\n id int(11) NOT NULL AUTO_INCREMENT,\n feature json NOT NULL,\n PRIMARY KEY (id)\n) ENGINE=InnoDB;<\/pre>\n<p>Une autre fa\u00e7on de stocker des documents JSON est de les mettre dans une colonne de type VARCHAR ou TEXT.<\/p>\n<p>La table <em>features_TEXT<\/em> va nous permettre de comparer les performances des types JSON et TEXT.<\/p>\n<pre class=\"lang:mysql decode:true\">CREATE TABLE features_TEXT (\n id int(11) NOT NULL AUTO_INCREMENT,\n feature longtext NOT NULL,\n PRIMARY KEY (id)\n) ENGINE=InnoDB;<\/pre>\n<p>Note: <em>Dans cet exemple le type\u00a0TEXT n&rsquo;est pas suffisamment large pour g\u00e9r\u00e9 nos donn\u00e9es JSON . (ERROR 1406 (22001): Data too long for column &lsquo;feature&rsquo; at row 17360). LONGTEXT fera donc l&rsquo;affaire<\/em>.<\/p>\n<h1>Insertion des donn\u00e9es dans les tables<\/h1>\n<p>Note: <em>Le temps d&rsquo;ex\u00e9cution d&rsquo;une m\u00eame\u00a0requ\u00eate pouvant varier largement d&rsquo;une ex\u00e9cution \u00e0 l&rsquo;autre, sur mon (vieux) portable avec une petite configuration pour MySQL (e.g. Buffer pool = 128Mo). J&rsquo;ai donc ex\u00e9cut\u00e9 les requ\u00eates plusieurs fois en utilisant <a href=\"https:\/\/dev.mysql.com\/doc\/refman\/5.7\/en\/mysqlslap.html\" target=\"_blank\" rel=\"noopener noreferrer\">mysqlslap<\/a>: <\/em><\/p>\n<p><em>mysqlslap -c1 -i &lt;N&gt; { Concurrence = 1 \/ It\u00e9ration &gt; 20 (en fonction de la dur\u00e9e totale de la requ\u00eate) }.<\/em><\/p>\n<p><em>Le temps d&rsquo;ex\u00e9cution sera donc repr\u00e9sent\u00e9 la plupart du temps sous la forme: \u00ab\u00a0Minimum number of seconds to run all queries: 59.392 seconds\u00a0\u00bb au lieu de \u00ab\u00a0Query OK, 206560 rows affected (59.39 sec)\u00a0\u00bb.<\/em><\/p>\n<p><span style=\"text-decoration: underline;\">Copier les donn\u00e9es JSON dans la table features<\/span><\/p>\n<pre class=\"lang:mysql decode:true\">LOAD DATA INFILE 'properties.json' INTO TABLE features (feature);<\/pre>\n<p><span style=\"color: #993300;\">Minimum number of seconds to run all queries: <b>59.392 seconds<\/b><\/span><\/p>\n<p><span style=\"text-decoration: underline;\">Copier les donn\u00e9es JSON dans la table features_TEXT<\/span><\/p>\n<pre class=\"lang:mysql decode:true\">LOAD DATA INFILE 'properties.json' INTO TABLE features_TEXT (feature);<\/pre>\n<p><span style=\"color: #993300;\">Minimum number of seconds to run all queries: <b>39.784 seconds<\/b><\/span><\/p>\n<p>Sur ma machine, charger 206560 enregistrements montre une diff\u00e9rence de performance d&rsquo;environ <strong>40%<\/strong> en faveur du type TEXT par rapport au type JSON.<\/p>\n<p>Cela s&rsquo;explique par les fonctionnalit\u00e9s fournit par le type JSON de MySQL:<\/p>\n<ul>\n<li><b>Validation automatique des documents JSON stock\u00e9s<\/b>. Tout document invalide produit une erreur.<\/li>\n<li><b>Optimisation du stockage des donn\u00e9es<\/b>. Les documents JSON stock\u00e9s dans des colonnes de type JSON sont convertis en un format interne qui permet un acc\u00e8s en lecture rapide.<\/li>\n<\/ul>\n<p>Bien \u00e9videmment rien de comparable pour le type TEXT, ces fonctionnalit\u00e9s ont donc un co\u00fbt lors de l&rsquo;\u00e9criture dans la table, ce qui est plut\u00f4t logique.<\/p>\n<p>Au niveau des m\u00e9ta-donn\u00e9es:<\/p>\n<pre class=\"lang:mysql decode:true\">SHOW TABLE STATUS LIKE 'features'\\G\n*************************** 1. row ***************************\n          Name: features\n        Engine: InnoDB\n       Version: 10\n    Row_format: Dynamic\n          Rows: 184218\nAvg_row_length: 1250\n   Data_length: 230326272  #220 MB\n  Index_length: 0\n     Data_free: 3145728<\/pre>\n<pre class=\"lang:mysql decode:true\">SHOW TABLE STATUS LIKE 'features_TEXT'\\G\n*************************** 1. row ***************************\n          Name: features_TEXT\n        Engine: InnoDB\n       Version: 10\n    Row_format: Dynamic\n          Rows: 188784\nAvg_row_length: 1370\n   Data_length: 258654208  #247 MB\n  Index_length: 0\n     Data_free: 4194304<\/pre>\n<p>Le point int\u00e9ressant ici est que le type de donn\u00e9es LONGTEXT consomme plus d&rsquo;espace que le type JSON (au format de stockage optimis\u00e9) environ <b>20% plus<\/b>.<\/p>\n<p>Note: <i>L&rsquo;insertion des documents JSON peut \u00e9galement se faire avec une requ\u00eate INSERT classique.<\/i><\/p>\n<p>e.g. (le champs doc est de type JSON)<\/p>\n<pre class=\"lang:mysql decode:true\">\u00a0INSERT INTO posts (doc) VALUES ('{\"_id\": \"42bfbd1958a7e6119733dc53609b8b8d\", \"text\": \"My first post!\", \"title\": \"MySQL rocks\"}');\n<\/pre>\n<h1>R\u00e9cup\u00e9rer des donn\u00e9es d&rsquo;un document JSON<\/h1>\n<p>MySQL 5.7 fournit un ensemble de <a href=\"http:\/\/dev.mysql.com\/doc\/refman\/5.7\/en\/json-functions.html\">fonctions JSON<\/a>.<\/p>\n<p>Par exemple, <a href=\"http:\/\/dev.mysql.com\/doc\/refman\/5.7\/en\/json-search-functions.html#function_json-extract\">JSON_EXTRACT<\/a> renvoi des donn\u00e9es d&rsquo;un document JSON. A noter que, depuis MySQL 5.7.9 vous pouvez utiliser la syntaxe <b>inlined JSON path expressions<\/b> qui rend plus lisible les requ\u00eates qui manipulent des donn\u00e9es JSON:<\/p>\n<p>e.g.<\/p>\n<p><span style=\"color: #0000ff;\">JSON_EXTRACT(col, \u00ab\u00a0$.json_field\u00a0\u00bb)<\/span> est similaire \u00e0<span style=\"color: #0000ff;\"> col<strong>-&gt;<\/strong>\u00ab\u00a0$.json_field\u00a0\u00bb<\/span><\/p>\n<p><span style=\"text-decoration: underline;\">Table avec type de donn\u00e9es JSON<\/span><\/p>\n<pre class=\"lang:default decode:true\">SELECT DISTINCT feature-&gt;\"$.type\" AS json_extract FROM features\\G\n*************************** 1. row ***************************\n          id: 1\n select_type: SIMPLE\n       table: features\n        type: ALL\npossible_keys: NULL\n         key: NULL\n     key_len: NULL\n         ref: NULL\n        rows: 182309\n    filtered: 100.00\n       Extra: Using temporary<\/pre>\n<p><span style=\"color: #993300;\">Minimum number of seconds to run all queries: <b>4.470 seconds<\/b><\/span><\/p>\n<p><span style=\"text-decoration: underline;\">Table avec type de donn\u00e9es TEXT<\/span><\/p>\n<pre class=\"lang:mysql decode:true\">SELECT DISTINCT feature-&gt;\"$.type\" AS json_extract FROM features_TEXT\\G\n*************************** 1. row ***************************\n          id: 1\n select_type: SIMPLE\n       table: features_TEXT\n        type: ALL\npossible_keys: NULL\n         key: NULL\n     key_len: NULL\n         ref: NULL\n        rows: 177803\n    filtered: 100.00\n       Extra: Using temporary<\/pre>\n<p><span style=\"color: #993300;\">Minimum number of seconds to run all queries: <b>29.365 seconds<\/b><\/span><\/p>\n<p><span style=\"text-decoration: underline;\">Remarques<\/span><\/p>\n<p>R\u00e9cup\u00e9rer les documents JSON implique, sans surprise, un Full Table Scan (FTS).<\/p>\n<p>Cependant on peut constater la puissance du format interne JSON de MySQL qui permet un acc\u00e8s en lecture particuli\u00e8rement rapide et efficace.<\/p>\n<p>Dans cet exemple\u00a0 le temps d&rsquo;ex\u00e9cution est environ <b>7 fois plus rapide<\/b> (<span style=\"color: #993300;\"><b>4.470 s<\/b><\/span> vs <span style=\"color: #993300;\"> <b>29.365 s<\/b><\/span>) avec le type de donn\u00e9es JSON compar\u00e9 aux m\u00eame donn\u00e9es stock\u00e9es dans une colonne de type TEXT.<\/p>\n<h1>Colonne g\u00e9n\u00e9r\u00e9e (Generated Column)<\/h1>\n<p>Une colonne de type JSON ne peut \u00eatre index\u00e9e. CEPENDANT il est possible de contourner cette restriction en cr\u00e9ant un index sur une <a href=\"http:\/\/dev.mysql.com\/doc\/refman\/5.7\/en\/create-table.html#create-table-secondary-indexes-virtual-columns\"><b>generated column<\/b><\/a> qui permet d&rsquo;extraire une valeur scalaire de la colonne JSON. Les <em>generated columns<\/em> peuvent \u00eatre stock\u00e9e \/ mat\u00e9rialis\u00e9e (STORED) ou virtuelle \/ non mat\u00e9rialis\u00e9e (VIRTUAL).<\/p>\n<p>Cr\u00e9er une <em>generated column<\/em> virtuelle (VIRTUAL) est tr\u00e8s rapide car les valeurs de la colonne ne sont pas stock\u00e9es mais calcul\u00e9es \u00e0 la vol\u00e9e lors de la lecture des enregistrements imm\u00e9diatement apr\u00e8s tout trigger BEFORE. Seules les m\u00e9ta-donn\u00e9es sont modifi\u00e9es en d&rsquo;autres termes, il n&rsquo;y a pas de reconstruction de la table.<\/p>\n<p>En production, c&rsquo;est en g\u00e9n\u00e9ral une colonne g\u00e9n\u00e9r\u00e9e virtuelle qui sera pertinente.<\/p>\n<pre class=\"lang:mysql decode:true\">ALTER TABLE features ADD feature_type VARCHAR(30) AS (feature-&gt;\"$.type\") VIRTUAL;\nQuery OK, 0 rows affected (0.08 sec)\nRecords: 0  Duplicates: 0  Warnings: 0<\/pre>\n<pre class=\"lang:mysql decode:true\">ALTER TABLE features_TEXT ADD feature_type VARCHAR(30) AS  (feature-&gt;\"$.type\") VIRTUAL;\nQuery OK, 0 rows affected (0.10 sec)\nRecords: 0  Duplicates: 0  Warnings: 0<\/pre>\n<p>Note: <i>Le d\u00e9savantage de cette approche est que certaines donn\u00e9es sont stock\u00e9es 2 fois; dans la colonne g\u00e9n\u00e9r\u00e9e et dans l&rsquo;index<\/i>.<\/p>\n<p>Les nouvelles structures de tables sont:<\/p>\n<pre class=\"lang:mysql decode:true \">CREATE TABLE features (\n id int(11) NOT NULL AUTO_INCREMENT,\n feature json NOT NULL,\n feature_type varchar(30) GENERATED ALWAYS AS (feature-&gt;\"$.type\") VIRTUAL,\n PRIMARY KEY (id)\n) ENGINE=InnoDB<\/pre>\n<pre class=\"lang:mysql decode:true\">CREATE TABLE features_TEXT (\n id int(11) NOT NULL AUTO_INCREMENT,\n feature longtext NOT NULL,\n feature_type varchar(30) GENERATED ALWAYS AS (feature-&gt;\"$.type\") VIRTUAL,\n PRIMARY KEY (id)\n) ENGINE=InnoDB<\/pre>\n<p>Au niveau des m\u00e9ta-donn\u00e9es:<\/p>\n<pre class=\"lang:mysql decode:true\">ANALYZE TABLE features, features_TEXT;\n\nSHOW TABLE STATUS LIKE 'features'\\G\n*************************** 1. row ***************************\n          Name: features\n        Engine: InnoDB\n       Version: 10\n    Row_format: Dynamic\n          Rows: 184218\nAvg_row_length: 1250\n   Data_length: 230326272  #220 MB\n  Index_length: 0\n     Data_free: 314572<\/pre>\n<pre class=\"lang:mysql decode:true\">SHOW TABLE STATUS LIKE 'features_TEXT'\\G\n*************************** 1. row ***************************\n          Name: features_TEXT\n        Engine: InnoDB\n       Version: 10\n    Row_format: Dynamic\n          Rows: 188784\nAvg_row_length: 1370\n   Data_length: 258654208  #247 MB\n  Index_length: 0\n     Data_free: 4194304<\/pre>\n<p><span style=\"text-decoration: underline;\">Remarques<\/span><\/p>\n<p>Identique !<\/p>\n<p>Comme on le pressentait la taille des donn\u00e9es n&rsquo;a pas chang\u00e9e.<\/p>\n<p>Y a t&rsquo;il une diff\u00e9rence de temps d&rsquo;ex\u00e9cution entre r\u00e9cup\u00e9rer des documents JSON \u00e0 partir de la colonne virtuelle et \u00e0 partir de la fonction JSON_EXTRACT ?<\/p>\n<pre class=\"lang:mysql decode:true\">SELECT DISTINCT feature_type FROM features\\G\n*************************** 1. row ***************************\n          id: 1\n select_type: SIMPLE\n       table: features\n        type: ALL\npossible_keys: NULL\n         key: NULL\n     key_len: NULL\n         ref: NULL\n        rows: 195195\n    filtered: 100.00\n       Extra: Using temporary<\/pre>\n<p><span style=\"color: #993300;\">Minimum number of seconds to run all queries: <b>2.790 seconds<\/b><\/span><\/p>\n<pre class=\"lang:mysql decode:true\">SELECT DISTINCT feature_type FROM features_TEXT\\G\n*************************** 1. row ***************************\n          id: 1\n select_type: SIMPLE\n       table: features_TEXT\n        type: ALL\npossible_keys: NULL\n         key: NULL\n     key_len: NULL\n         ref: NULL\n        rows: 171004\n    filtered: 100.00\n       Extra: Using temporary<\/pre>\n<p><span style=\"color: #993300;\">Minimum number of seconds to run all queries: <b>25.933 seconds<\/b><\/span><\/p>\n<p><span style=\"text-decoration: underline;\">Remarques<\/span><\/p>\n<p>\u00c9videmment le plan d&rsquo;ex\u00e9cution (QEP) est le m\u00eame: FTS.<\/p>\n<p>Cependant 2 commentaires:<\/p>\n<ul>\n<li>Le type de donn\u00e9es JSON de MySQL est encore plus efficace que le type de donn\u00e9es TEXT, dans cet exemple le temps d&rsquo;ex\u00e9cution est environ <b>8 fois plus rapide avec <\/b>JSON.<\/li>\n<\/ul>\n<ul>\n<li>Un FTS sur une <em>generated column<\/em> virtuelle (colonne: feature_type) est plus performant que l&rsquo;utilisation,\u00a0dans la clause du SELECT, de la fonction json_extract sur le document JSON (de <b>4.470<\/b> \u00e0 <b>2.790<\/b>).<\/li>\n<\/ul>\n<h1>Cr\u00e9er un index sur une colonne g\u00e9n\u00e9r\u00e9e<\/h1>\n<p>A partir de MySQL 5.7.8, InnoDB supporte les index secondaires sur les colonnes virtuelles.<\/p>\n<p>Ajouter ou supprimer un index secondaire dans une colonne virtuelle est une op\u00e9ration qui ne n\u00e9cessite pas de recopier la table (in-place operation).<\/p>\n<pre class=\"lang:mysql decode:true\">ALTER TABLE features ADD INDEX (feature_type);\nQuery OK, 0 rows affected (5.04 sec)\nRecords: 0  Duplicates: 0  Warnings: 0<\/pre>\n<pre class=\"lang:mysql decode:true\">ALTER TABLE features_TEXT ADD INDEX (feature_type);\nQuery OK, 0 rows affected (27.89 sec)\nRecords: 0  Duplicates: 0  Warnings: 0<\/pre>\n<p>La nouvelle structure des tables est:<\/p>\n<pre class=\"lang:mysql decode:true\">CREATE TABLE features (\n id` int(11) NOT NULL AUTO_INCREMENT,\n feature` json NOT NULL,\n feature_type varchar(30) GENERATED ALWAYS AS (feature-&gt;\"$.type\") VIRTUAL,\n PRIMARY KEY (id),\n KEY feature_type (feature_type)\n) ENGINE=InnoDB<\/pre>\n<pre class=\"lang:mysql decode:true \">CREATE TABLE features_TEXT (\n id int(11) NOT NULL AUTO_INCREMENT,\n feature longtext NOT NULL,\n feature_type varchar(30) GENERATED ALWAYS AS (feature-&gt;\"$.type\") VIRTUAL,\n PRIMARY KEY (id),\n KEY feature_type (feature_type)\n) ENGINE=InnoDB<\/pre>\n<p>Au niveau des m\u00e9ta-donn\u00e9es:<\/p>\n<pre class=\"lang:mysql decode:true\">ANALYZE TABLE features, features_TEXT;\n\nSHOW TABLE STATUS LIKE 'features'\\G\n*************************** 1. row ***************************\n          Name: features\n        Engine: InnoDB\n       Version: 10\n    Row_format: Dynamic\n          Rows: 180400\nAvg_row_length: 1276\n   Data_length: 230326272  #220 MB\n  Index_length: 5783552    #6 MB\n     Data_free: 5242880<\/pre>\n<pre class=\"lang:mysql decode:true \">SHOW TABLE STATUS LIKE 'features_TEXT'\\G\n*************************** 1. row ***************************\n          Name: features_TEXT\n        Engine: InnoDB\n       Version: 10\n    Row_format: Dynamic\n          Rows: 192445\nAvg_row_length: 1344\n   Data_length: 258654208  #247 MB\n  Index_length: 5783552    #6 MB\n     Data_free: 2097152<\/pre>\n<p><span style=\"text-decoration: underline;\">Remarque<\/span><\/p>\n<p>L&rsquo;index sur la colonne <i>feature_type<\/i> est mat\u00e9rialis\u00e9. Sa taille est approximativement 6 Mo.<\/p>\n<p>Gr\u00e2ce \u00e0 l&rsquo;index, la requ\u00eate devrait \u00eatre plus efficace:<\/p>\n<pre class=\"lang:mysql decode:true\">SELECT DISTINCT feature_type FROM features\\G\n*************************** 1. row ***************************\n          id: 1\n select_type: SIMPLE\n       table: features\n        type: index\npossible_keys: feature_type\n         key: feature_type\n     key_len: 33\n         ref: NULL\n        rows: 193763\n    filtered: 100.00\n       Extra: Using index<\/pre>\n<p><span style=\"color: #993300;\">Minimum number of seconds to run all queries: <b>0.178<\/b> seconds<\/span><\/p>\n<pre class=\"lang:mysql decode:true \">SELECT DISTINCT feature_type FROM features_TEXT\\G\n*************************** 1. row ***************************\n          id: 1\n select_type: SIMPLE\n       table: features_TEXT\n        type: index\npossible_keys: feature_type\n         key: feature_type\n     key_len: 33\n         ref: NULL\n        rows: 208134\n    filtered: 100.00\n       Extra: Using index<\/pre>\n<p><span style=\"color: #993300;\">Minimum number of seconds to run all queries: <b>0.178<\/b> seconds<\/span><\/p>\n<p>Comme pr\u00e9vu, l&rsquo;optimiseur utilise l&rsquo;index (feature_type) et la temps d&rsquo;ex\u00e9cution de la requ\u00eate est vraiment meilleur, et ce pour les 2 tables (de <b>2.790<\/b> \u00e0 <b>0.178<\/b> pour la colonne JSON).<\/p>\n<h1>Pour conclure<\/h1>\n<p>MySQL 5.7 impl\u00e9mente le type de donn\u00e9es JSON, ainsi qu&rsquo;un ensemble de fonctions qui permet de <b>Cr\u00e9er<\/b>, <b>Chercher<\/b>, <b>Modifier<\/b> des valeurs JSON mais \u00e9galement de <b>Renvoyer<\/b> des valeur d&rsquo;attributs<b> <\/b>JSON. C&rsquo;est une superbe fonctionnalit\u00e9 et je suis persuad\u00e9 que les d\u00e9veloppeurs sauront en faire bon usage.<\/p>\n<p>La colonne g\u00e9n\u00e9r\u00e9e (Generated Columns) est \u00e9galement une fonctionnalit\u00e9 tr\u00e8s utile. Elle peut \u00eatre utilis\u00e9e, entre autre, pour indexer une fonction, ou comme cache pour expressions souvent utilis\u00e9es, ou pour indexer du contenu XML&#8230; ou comme nous venons de le voir pour indexer des documents JSON.<\/p>\n<p>MySQL 5.7 est vraiment une superbe version !\u00a0 Essayez la, elle m\u00e9rite d\u00e9finitivement plus de 30 minutes.<\/p>\n<p>Vous voulez en savoir plus sur MySQL 5.7?<\/p>\n<ul>\n<li><span style=\"color: #ff0000;\"><strong>8 d\u00e9cember 2015, @Paris <\/strong><span style=\"color: #000000;\">rejoignez nous sur l<\/span><\/span><span style=\"color: #ff0000;\"><span style=\"color: #000000;\">&lsquo;<\/span><\/span><strong><span style=\"color: #ff0000;\"><span style=\"color: #333399;\"><span style=\"color: #ff0000;\"><a style=\"color: #ff0000;\" href=\"https:\/\/t.co\/MD6xBB4hKS\" target=\"_blank\" rel=\"noopener noreferrer\">Oracle MySQL Tech Tour Paris<\/a><\/span> \u00a0<\/span><\/span><\/strong><\/li>\n<li><span style=\"color: #333399;\">Other location: <a style=\"color: #333399;\" href=\"http:\/\/www.oracle.com\/events\/emea\/en\/mysql-tech-tour\/index.html\" target=\"_blank\" rel=\"noopener noreferrer\">Oracle MySQL Tech Tour<\/a><\/span><\/li>\n<\/ul>\n<h1>Pour aller plus loin<\/h1>\n<ul>\n<li><strong><a href=\"http:\/\/dasini.net\/blog\/2018\/07\/23\/30-mins-avec-les-fonctions-json-de-mysql\/\" target=\"_blank\" rel=\"noopener noreferrer\">30 mins avec les fonctions JSON de MySQL<\/a><\/strong><\/li>\n<\/ul>\n<h2>MySQL Documentation<\/h2>\n<h3>The JSON data type<\/h3>\n<p><a href=\"https:\/\/dev.mysql.com\/doc\/refman\/5.7\/en\/json.html\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/dev.mysql.com\/doc\/refman\/5.7\/en\/json.html<\/a><\/p>\n<h3>JSON Functions<\/h3>\n<p><a href=\"https:\/\/dev.mysql.com\/doc\/refman\/5.7\/en\/json-functions.html\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/dev.mysql.com\/doc\/refman\/5.7\/en\/json-functions.html<\/a><\/p>\n<h3>CREATE TABLE and Generated Columns<\/h3>\n<p><a href=\"http:\/\/dev.mysql.com\/doc\/refman\/5.7\/en\/create-table.html#create-table-generated-columns\" target=\"_blank\" rel=\"noopener noreferrer\">http:\/\/dev.mysql.com\/doc\/refman\/5.7\/en\/create-table.html#create-table-generated-columns<\/a><\/p>\n<h2>MySQL Server Blog<\/h2>\n<h3>Native JSON Data Type and Binary Format<\/h3>\n<p><a href=\"http:\/\/mysqlserverteam.com\/json-labs-release-native-json-data-type-and-binary-format\/\" target=\"_blank\" rel=\"noopener noreferrer\">http:\/\/mysqlserverteam.com\/json-labs-release-native-json-data-type-and-binary-format\/<\/a><\/p>\n<h3>JSON functions<\/h3>\n<p><a href=\"http:\/\/mysqlserverteam.com\/json-labs-release-json-functions-part-1-manipulation-json-data\/\" target=\"_blank\" rel=\"noopener noreferrer\">http:\/\/mysqlserverteam.com\/json-labs-release-json-functions-part-1-manipulation-json-data\/<\/a><\/p>\n<p><a href=\"http:\/\/mysqlserverteam.com\/mysql-5-7-lab-release-json-functions-part-2-querying-json-data\/\" target=\"_blank\" rel=\"noopener noreferrer\">http:\/\/mysqlserverteam.com\/mysql-5-7-lab-release-json-functions-part-2-querying-json-data\/<\/a><\/p>\n<p><a href=\"https:\/\/mysqlserverteam.com\/new-json-functions-in-mysql-5-7-22\/\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/mysqlserverteam.com\/new-json-functions-in-mysql-5-7-22\/<\/a><\/p>\n<h3>Inline JSON Path Expressions in MySQL 5.7<\/h3>\n<p><a href=\"http:\/\/mysqlserverteam.com\/inline-json-path-expressions-in-mysql-5-7\/\" target=\"_blank\" rel=\"noopener noreferrer\">http:\/\/mysqlserverteam.com\/inline-json-path-expressions-in-mysql-5-7\/<\/a><\/p>\n<h3>Getting Started With MySQL &amp; JSON on Windows<\/h3>\n<p><a href=\"http:\/\/mysqlserverteam.com\/getting-started-with-mysql-json-on-windows\/\" target=\"_blank\" rel=\"noopener noreferrer\">http:\/\/mysqlserverteam.com\/getting-started-with-mysql-json-on-windows\/<\/a><\/p>\n<h3>Effective Functional Indexes in InnoDB<\/h3>\n<p><a href=\"http:\/\/mysqlserverteam.com\/json-labs-release-effective-functional-indexes-in-innodb\/\" target=\"_blank\" rel=\"noopener noreferrer\">http:\/\/mysqlserverteam.com\/json-labs-release-effective-functional-indexes-in-innodb\/<\/a><\/p>\n<h2>MySQL 5.7<\/h2>\n<h3>What Is New in MySQL 5.7<\/h3>\n<p><a href=\"https:\/\/dev.mysql.com\/doc\/refman\/5.7\/en\/mysql-nutshell.html\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/dev.mysql.com\/doc\/refman\/5.7\/en\/mysql-nutshell.html<\/a><\/p>\n<h3>Complete list of new features in MySQL 5.7<\/h3>\n<p><a href=\"http:\/\/www.thecompletelistoffeatures.com\/\" target=\"_blank\" rel=\"noopener noreferrer\">http:\/\/www.thecompletelistoffeatures.com\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Comme vous le savez MySQL 5.7 est GA. Cette nouvelle mouture de la base de donn\u00e9es open source la plus populaire au monde a plus de 150 nouvelles fonctionnalit\u00e9s. L&rsquo;une d&rsquo;entre elle est un type de donn\u00e9es JSON natif ainsi que les fonctions JSON associ\u00e9es.<\/p>\n<p>Prenons 30 minutes pour voir ce que cela donne&#8230;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"footnotes":""},"categories":[260,8],"tags":[262,278,276],"class_list":["post-1533","post","type-post","status-publish","format-standard","hentry","category-json-fr","category-mysql","tag-generated-column","tag-json","tag-nosql"],"aioseo_notices":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p9LfWW-oJ","jetpack-related-posts":[{"id":2959,"url":"https:\/\/dasini.net\/blog\/2019\/04\/08\/200\/","url_meta":{"origin":1533,"position":0},"title":"200 !!","author":"Olivier DASINI","date":"8 avril 2019","format":false,"excerpt":"Cet article est en fait mon 200 \u00e8me \\o\/ Pour marquer le coup, j'ai d\u00e9cid\u00e9 de faire une petite pause et de regarder dans le r\u00e9troviseur...","rel":"","context":"Dans &quot;Divers&quot;","block_context":{"text":"Divers","link":"https:\/\/dasini.net\/blog\/category\/divers\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2492,"url":"https:\/\/dasini.net\/blog\/2018\/07\/23\/30-mins-avec-les-fonctions-json-de-mysql\/","url_meta":{"origin":1533,"position":1},"title":"30 mins avec les fonctions JSON de MySQL","author":"Olivier DASINI","date":"23 juillet 2018","format":false,"excerpt":"Comme tu le sais,\u00a0JSON (JavaScript Object Notation) est un populaire format d'\u00e9change de donn\u00e9es. Depuis la version 5.7, MySQL supporte un type de donn\u00e9es JSON\u00a0natif (au format interne binaire pour des raisons d'efficacit\u00e9s), ainsi qu'un riche ensemble de fonctions qui te permettront de manipuler dans tout les sens tes documents\u2026","rel":"","context":"Dans &quot;json&quot;","block_context":{"text":"json","link":"https:\/\/dasini.net\/blog\/category\/json-fr\/"},"img":{"alt_text":"MySQL native JSON data type","src":"https:\/\/i0.wp.com\/dasini.net\/blog\/wp-content\/uploads\/json_icon.png?resize=350%2C200","width":350,"height":200},"classes":[]},{"id":1557,"url":"https:\/\/dasini.net\/blog\/2015\/11\/30\/json-et-colonnes-generees-avec-mysql\/","url_meta":{"origin":1533,"position":2},"title":"JSON et colonnes g\u00e9n\u00e9r\u00e9es avec MySQL","author":"Olivier DASINI","date":"30 novembre 2015","format":false,"excerpt":"Le 24 novembre dernier, lors du Forum PHP, Tomas Ulin (Oracle's MySQL VP of Engineering) a parl\u00e9 de l'utilisation de JSON dans MySQL \"MySQL 5.7 & JSON: New opportunities for developers\". Voici les r\u00e9ponses \u00e0 quelques questions qui m'ont \u00e9t\u00e9 pos\u00e9es: Comment se comporte mysqldump avec les colonnes g\u00e9n\u00e9r\u00e9es ?\u2026","rel":"","context":"Dans &quot;json&quot;","block_context":{"text":"json","link":"https:\/\/dasini.net\/blog\/category\/json-fr\/"},"img":{"alt_text":"JSON","src":"https:\/\/i0.wp.com\/dasini.net\/blog\/wp-content\/uploads\/json_icon.png?resize=350%2C200","width":350,"height":200},"classes":[]},{"id":1634,"url":"https:\/\/dasini.net\/blog\/2016\/08\/29\/meetup-mysql-group-replication-mysql-as-a-document-store\/","url_meta":{"origin":1533,"position":3},"title":"Meetup &#8211; MySQL Group Replication &#038; MySQL as a Document Store","author":"Olivier DASINI","date":"29 ao\u00fbt 2016","format":false,"excerpt":"Oracle MySQL, Openska et Executive MBA Epitech ont le plaisir de vous inviter le mardi 6 septembre pour le premier meetup MySQL de la rentr\u00e9e. Au programme: MySQL Group Replication & MySQL as a Document Store","rel":"","context":"Dans &quot;Conf\u00e9rence&quot;","block_context":{"text":"Conf\u00e9rence","link":"https:\/\/dasini.net\/blog\/category\/conference\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/mysqlhighavailability.com\/wp-content\/uploads\/2014\/09\/1.png?resize=350%2C200","width":350,"height":200},"classes":[]},{"id":1620,"url":"https:\/\/dasini.net\/blog\/2016\/04\/21\/mysql-en-tant-que-document-store\/","url_meta":{"origin":1533,"position":4},"title":"MySQL en tant que Document Store","author":"Olivier DASINI","date":"21 avril 2016","format":false,"excerpt":"A partir de MySQL 5.7.12, la nouvelle version de la base de donn\u00e9es la plus populaire, Les devs and DBAs peuvent maintenant d\u00e9ployer des bases MySQL qui impl\u00e9mentent un mod\u00e8le document store, relationnel ou hybride (document ET relationnel) ! Plus d'info: http:\/\/dev.mysql.com\/doc\/refman\/5.7\/en\/document-store.ht","rel":"","context":"Dans &quot;MySQL&quot;","block_context":{"text":"MySQL","link":"https:\/\/dasini.net\/blog\/category\/mysql\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2450,"url":"https:\/\/dasini.net\/blog\/2018\/07\/12\/nouveaux-livres-mysql\/","url_meta":{"origin":1533,"position":5},"title":"Nouveaux livres MySQL","author":"Olivier DASINI","date":"12 juillet 2018","format":false,"excerpt":"Jadis, lorsque l'on voulait approfondir un sujet technique, il nous fallait \u00e0 tout prix LE livre (celui l\u00e0\u00a0\u00e0 litt\u00e9ralement chang\u00e9 ma vie, et ce n'est pas le seul: celui l\u00e0, celui l\u00e0,...). De nos jours, des milliards de ressources sont disponibles gratuitement sur internet, mais il faut bien l'avouer, la\u2026","rel":"","context":"Dans &quot;Divers&quot;","block_context":{"text":"Divers","link":"https:\/\/dasini.net\/blog\/category\/divers\/"},"img":{"alt_text":"MySQL and JSON: A Practical Programming Guide - Discover how to use JavaScript Object Notation (JSON) with MySQL","src":"https:\/\/i0.wp.com\/images-na.ssl-images-amazon.com\/images\/I\/416UKa-bH%2BL._SX332_BO1%2C204%2C203%2C200_.jpg?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]}],"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/dasini.net\/blog\/wp-json\/wp\/v2\/posts\/1533","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dasini.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dasini.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dasini.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/dasini.net\/blog\/wp-json\/wp\/v2\/comments?post=1533"}],"version-history":[{"count":16,"href":"https:\/\/dasini.net\/blog\/wp-json\/wp\/v2\/posts\/1533\/revisions"}],"predecessor-version":[{"id":7239,"href":"https:\/\/dasini.net\/blog\/wp-json\/wp\/v2\/posts\/1533\/revisions\/7239"}],"wp:attachment":[{"href":"https:\/\/dasini.net\/blog\/wp-json\/wp\/v2\/media?parent=1533"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dasini.net\/blog\/wp-json\/wp\/v2\/categories?post=1533"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dasini.net\/blog\/wp-json\/wp\/v2\/tags?post=1533"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}