Rechercher dans le manuel MySQL

13.1.20.10 Secondary Indexes and Generated Columns

InnoDB supports secondary indexes on virtual generated columns. Other index types are not supported. A secondary index defined on a virtual column is sometimes referred to as a virtual index.

A secondary index may be created on one or more virtual columns or on a combination of virtual columns and regular columns or stored generated columns. Secondary indexes that include virtual columns may be defined as UNIQUE.

When a secondary index is created on a virtual generated column, generated column values are materialized in the records of the index. If the index is a covering index (one that includes all the columns retrieved by a query), generated column values are retrieved from materialized values in the index structure instead of computed on the fly.

There are additional write costs to consider when using a secondary index on a virtual column due to computation performed when materializing virtual column values in secondary index records during INSERT and UPDATE operations. Even with additional write costs, secondary indexes on virtual columns may be preferable to generated stored columns, which are materialized in the clustered index, resulting in larger tables that require more disk space and memory. If a secondary index is not defined on a virtual column, there are additional costs for reads, as virtual column values must be computed each time the column's row is examined.

Values of an indexed virtual column are MVCC-logged to avoid unnecessary recomputation of generated column values during rollback or during a purge operation. The data length of logged values is limited by the index key limit of 767 bytes for COMPACT and REDUNDANT row formats, and 3072 bytes for DYNAMIC and COMPRESSED row formats.

Adding or dropping a secondary index on a virtual column is an in-place operation.

Indexing a Generated Column to Provide a JSON Column Index

As noted elsewhere, JSON columns cannot be indexed directly. To create an index that references such a column indirectly, you can define a generated column that extracts the information that should be indexed, then create an index on the generated column, as shown in this example:

  1. mysql> CREATE TABLE jemp (
  2.     ->     c JSON,
  3.     ->     g INT GENERATED ALWAYS AS (c->"$.id")),
  4.     ->     INDEX i (g)
  5.     -> );
  6. Query OK, 0 rows affected (0.28 sec)
  7.  
  8. mysql> INSERT INTO jemp (c) VALUES
  9.      >   ('{"id": "1", "name": "Fred"}'), ('{"id": "2", "name": "Wilma"}'),
  10.      >   ('{"id": "3", "name": "Barney"}'), ('{"id": "4", "name": "Betty"}');
  11. Query OK, 4 rows affected (0.04 sec)
  12. Records: 4  Duplicates: 0  Warnings: 0
  13.  
  14. mysql> SELECT c->>"$.name" AS name
  15.      >     FROM jemp WHERE g > 2;
  16. +--------+
  17. | name   |
  18. +--------+
  19. | Barney |
  20. | Betty  |
  21. +--------+
  22. 2 rows in set (0.00 sec)
  23.  
  24. mysql> EXPLAIN SELECT c->>"$.name" AS name
  25.      >    FROM jemp WHERE g > 2\G
  26. *************************** 1. row ***************************
  27.            id: 1
  28.   select_type: SIMPLE
  29.         table: jemp
  30.    partitions: NULL
  31.          type: range
  32. possible_keys: i
  33.           key: i
  34.       key_len: 5
  35.           ref: NULL
  36.          rows: 2
  37.      filtered: 100.00
  38.         Extra: Using where
  39. 1 row in set, 1 warning (0.00 sec)
  40.  
  41. mysql> SHOW WARNINGS\G
  42. *************************** 1. row ***************************
  43.   Level: Note
  44.    Code: 1003
  45. Message: /* select#1 */ select json_unquote(json_extract(`test`.`jemp`.`c`,'$.name'))
  46. AS `name` from `test`.`jemp` where (`test`.`jemp`.`g` > 2)
  47. 1 row in set (0.00 sec)

(We have wrapped the output from the last statement in this example to fit the viewing area.)

When you use EXPLAIN on a SELECT or other SQL statement containing one or more expressions that use the -> or ->> operator, these expressions are translated into their equivalents using JSON_EXTRACT() and (if needed) JSON_UNQUOTE() instead, as shown here in the output from SHOW WARNINGS immediately following this EXPLAIN statement:

  1. mysql> EXPLAIN SELECT c->>"$.name"
  2.      > FROM jemp WHERE g > 2 ORDER BY c->"$.name"\G
  3. *************************** 1. row ***************************
  4.            id: 1
  5.   select_type: SIMPLE
  6.         table: jemp
  7.    partitions: NULL
  8.          type: range
  9. possible_keys: i
  10.           key: i
  11.       key_len: 5
  12.           ref: NULL
  13.          rows: 2
  14.      filtered: 100.00
  15.         Extra: Using where; Using filesort
  16. 1 row in set, 1 warning (0.00 sec)
  17.  
  18. mysql> SHOW WARNINGS\G
  19. *************************** 1. row ***************************
  20.   Level: Note
  21.    Code: 1003
  22. Message: /* select#1 */ select json_unquote(json_extract(`test`.`jemp`.`c`,'$.name')) AS
  23. `c->>"$.name"` from `test`.`jemp` where (`test`.`jemp`.`g` > 2) order by
  24. json_extract(`test`.`jemp`.`c`,'$.name')
  25. 1 row in set (0.00 sec)

See the descriptions of the -> and ->> operators, as well as those of the JSON_EXTRACT() and JSON_UNQUOTE() functions, for additional information and examples.

This technique also can be used to provide indexes that indirectly reference columns of other types that cannot be indexed directly, such as GEOMETRY columns.

Table des matières Haut

JSON columns and indirect indexing in NDB Cluster

It is also possible to use indirect indexing of JSON columns in MySQL NDB Cluster, subject to the following conditions:

  1. NDB handles a JSON column value internally as a BLOB. This means that any NDB table having one or more JSON columns must have a primary key, else it cannot be recorded in the binary log.

  2. The NDB storage engine does not support indexing of virtual columns. Since the default for generated columns is VIRTUAL, you must specify explicitly the generated column to which to apply the indirect index as STORED.

The CREATE TABLE statement used to create the table jempn shown here is a version of the jemp table shown previously, with modifications making it compatible with NDB:

  1. CREATE TABLE jempn (
  2.   c JSON DEFAULT NULL,
  3.   g INT GENERATED ALWAYS AS (c->"$.name") STORED,
  4.   INDEX i (g)
  5. ) ENGINE=NDB;

We can populate this table using the following INSERT statement:

  1. INSERT INTO jempn (a, c) VALUES  
  2.   (NULL, '{"id": "1", "name": "Fred"}'),
  3.   (NULL, '{"id": "2", "name": "Wilma"}'),  
  4.   (NULL, '{"id": "3", "name": "Barney"}'),
  5.   (NULL, '{"id": "4", "name": "Betty"}');

Now NDB can use index i, as shown here:

  1. mysql> EXPLAIN SELECT c->>"$.name" AS name        
  2.           FROM jempn WHERE g > 2\G
  3. *************************** 1. row ***************************
  4.            id: 1
  5.   select_type: SIMPLE
  6.         table: jempn
  7.    partitions: p0,p1
  8.          type: range
  9. possible_keys: i
  10.           key: i
  11.       key_len: 5
  12.           ref: NULL
  13.          rows: 3
  14.      filtered: 100.00
  15.         Extra: Using where with pushed condition (`test`.`jempn`.`g` > 2)
  16. 1 row in set, 1 warning (0.00 sec)
  17.  
  18. mysql> SHOW WARNINGS\G
  19. *************************** 1. row ***************************
  20.   Level: Note
  21.    Code: 1003
  22. Message: /* select#1 */ select
  23. json_unquote(json_extract(`test`.`jempn`.`c`,'$.name')) AS `name` from
  24. `test`.`jempn` where (`test`.`jempn`.`g` > 2)  
  25. 1 row in set (0.00 sec)

You should keep in mind that a stored generated column uses DataMemory, and that an index on such a column uses IndexMemory.


Rechercher dans le manuel MySQL

Traduction non disponible

Le manuel MySQL n'est pas encore traduit en français sur l'infobrol. Seule la version anglaise est disponible pour l'instant.

Document créé le 26/06/2006, dernière modification le 26/10/2018
Source du document imprimé : https://www.gaudry.be/mysql-rf-create-table-secondary-indexes.html

L'infobrol est un site personnel dont le contenu n'engage que moi. Le texte est mis à disposition sous licence CreativeCommons(BY-NC-SA). Plus d'info sur les conditions d'utilisation et sur l'auteur.

Références

  1. Consulter le document html Langue du document :en Manuel MySQL : https://dev.mysql.com/

Ces références et liens indiquent des documents consultés lors de la rédaction de cette page, ou qui peuvent apporter un complément d'information, mais les auteurs de ces sources ne peuvent être tenus responsables du contenu de cette page.
L'auteur de ce site est seul responsable de la manière dont sont présentés ici les différents concepts, et des libertés qui sont prises avec les ouvrages de référence. N'oubliez pas que vous devez croiser les informations de sources multiples afin de diminuer les risques d'erreurs.

Table des matières Haut