Rechercher dans le manuel MySQL
13.1.15 CREATE INDEX Syntax
- [index_type]
- [index_option]
- [algorithm_option | lock_option] ...
- index_option:
- | index_type
- | WITH PARSER parser_name
- | {VISIBLE | INVISIBLE}
- index_type:
- algorithm_option:
- lock_option:
Normally, you create all indexes on a table at the time the table
itself is created with CREATE
TABLE
. See Section 13.1.20, “CREATE TABLE Syntax”. This
guideline is especially important for
InnoDB
tables, where the primary key
determines the physical layout of rows in the data file.
CREATE INDEX
enables you to add
indexes to existing tables.
CREATE INDEX
is mapped to an
ALTER TABLE
statement to create
indexes. See Section 13.1.9, “ALTER TABLE Syntax”.
CREATE INDEX
cannot be used to
create a PRIMARY KEY
; use
ALTER TABLE
instead. For more
information about indexes, see Section 8.3.1, “How MySQL Uses Indexes”.
InnoDB
supports secondary indexes on
virtual columns. For more information, see
Section 13.1.20.9, “Secondary Indexes and Generated Columns”.
When the innodb_stats_persistent
setting is enabled, run the ANALYZE
TABLE
statement for an
InnoDB
table after creating an index
on that table.
An index specification of the form
(
creates an
index with multiple key parts. Index key values are formed by
concatenating the values of the given key parts. For example
key_part1
,
key_part2
, ...)(col1, col2, col3)
specifies a multiple-column
index with index keys consisting of values from
col1
, col2
, and
col3
.
A key_part
specification can end with
ASC
or DESC
to specify
whether index values are stored in ascending or descending order.
The default is ascending if no order specifier is given.
ASC
and DESC
are not
permitted for HASH
indexes. As of MySQL 8.0.12,
ASC
and DESC
are not
permitted for SPATIAL
indexes.
The following sections describe different aspects of the
CREATE INDEX
statement:
Column Prefix Key Parts
For string columns, indexes can be created that use only the
leading part of column values, using
syntax to specify an index prefix length:
col_name
(length
)
Prefixes can be specified for
CHAR
,VARCHAR
,BINARY
, andVARBINARY
key parts.Prefixes must be specified for
BLOB
andTEXT
key parts. Additionally,BLOB
andTEXT
columns can be indexed only forInnoDB
,MyISAM
, andBLACKHOLE
tables.Prefix limits are measured in bytes. However, prefix lengths for index specifications in
CREATE TABLE
,ALTER TABLE
, andCREATE INDEX
statements are interpreted as number of characters for nonbinary string types (CHAR
,VARCHAR
,TEXT
) and number of bytes for binary string types (BINARY
,VARBINARY
,BLOB
). Take this into account when specifying a prefix length for a nonbinary string column that uses a multibyte character set.Prefix support and lengths of prefixes (where supported) are storage engine dependent. For example, a prefix can be up to 767 bytes long for
InnoDB
tables that use theREDUNDANT
orCOMPACT
row format. The prefix length limit is 3072 bytes forInnoDB
tables that use theDYNAMIC
orCOMPRESSED
row format. ForMyISAM
tables, the prefix length limit is 1000 bytes. TheNDB
storage engine does not support prefixes (see Section 22.1.7.6, “Unsupported or Missing Features in NDB Cluster”).
If a specified index prefix exceeds the maximum column data type
size, CREATE INDEX
handles the
index as follows:
For a nonunique index, either an error occurs (if strict SQL mode is enabled), or the index length is reduced to lie within the maximum column data type size and a warning is produced (if strict SQL mode is not enabled).
For a unique index, an error occurs regardless of SQL mode because reducing the index length might enable insertion of nonunique entries that do not meet the specified uniqueness requirement.
The statement shown here creates an index using the first 10
characters of the name
column (assuming that
name
has a nonbinary string type):
If names in the column usually differ in the first 10
characters, lookups performed using this index should not be
much slower than using an index created from the entire
name
column. Also, using column prefixes for
indexes can make the index file much smaller, which could save a
lot of disk space and might also speed up
INSERT
operations.
A “normal” index indexes column values or prefixes
of column values. For example, in the following table, the index
entry for a given t1
row includes the full
col1
value and a prefix of the
col2
value consisting of its first 10 bytes:
MySQL 8.0.13 and higher supports functional key parts that index expression values rather than column or column prefix values. Use of functional key parts enables indexing of values not stored directly in the table. Examples:
An index with multiple key parts can mix nonfunctional and functional key parts.
ASC
and DESC
are supported
for functional key parts.
Functional key parts must adhere to the following rules. An error occurs if a key part definition contains disallowed constructs.
In index definitions, enclose expressions within parentheses to distinguish them from columns or column prefixes. For example, this is permitted; the expressions are enclosed within parentheses:
This produces an error; the expressions are not enclosed within parentheses:
A functional key part cannot consist solely of a column name. For example, this is not permitted:
INDEX ((col1), (col2))
Instead, write the key parts as nonfunctional key parts, without parentheses:
INDEX (col1, col2)
A functional key part expression cannot refer to column prefixes. For a workaround, see the discussion of
SUBSTRING()
andCAST()
later in this section.Functional key parts are not permitted in foreign key specifications.
For CREATE
TABLE ... LIKE
, the destination table preserves
functional key parts from the original table.
Functional indexes are implemented as hidden virtual generated columns, which has these implications:
Each functional key part counts against the limit on total number of table columns; see Section C.10.4, “Limits on Table Column Count and Row Size”.
Functional key parts inherit all restrictions that apply to generated columns. Examples:
Only functions permitted for generated columns are permitted for functional key parts.
Subqueries, parameters, variables, stored functions, and user-defined functions are not permitted.
For more information about applicable restrictions, see Section 13.1.20.8, “CREATE TABLE and Generated Columns”, and Section 13.1.9.2, “ALTER TABLE and Generated Columns”.
UNIQUE
is supported for indexes that include
functional key parts. However, primary keys cannot include
functional key parts. A primary key requires the generated
column to be stored, but functional key parts are implemented as
virtual generated columns, not stored generated columns.
SPATIAL
and FULLTEXT
indexes cannot have functional key parts.
If a table contains no primary key, InnoDB
automatically promotes the first UNIQUE NOT
NULL
index to the primary key. This is not supported
for UNIQUE NOT NULL
indexes that have
functional key parts.
Nonfunctional indexes raise a warning if there are duplicate indexes. Indexes that contain functional key parts do not have this feature.
To remove a column that is referenced by a functional key part, the index must be removed first. Otherwise, an error occurs.
Although nonfunctional key parts support a prefix length
specification, this is not possible for functional key parts.
The solution is to use
SUBSTRING()
(or
CAST()
, as described later in
this section). For a functional key part containing the
SUBSTRING()
function to be used
in a query, the WHERE
clause must contain
SUBSTRING()
with the same
arguments. In the following example, only the second
SELECT
is able to use the index
because that is the only query in which the arguments to
SUBSTRING()
match the index
specification:
- col1 LONGTEXT,
- );
Functional key parts enable indexing of values that cannot be
indexed otherwise, such as JSON
values. However, this must be done correctly to achieve the
desired effect. For example, this syntax does not work:
The syntax fails because:
The
->>
operator translates intoJSON_UNQUOTE(JSON_EXTRACT(...))
.JSON_UNQUOTE()
returns a value with a data type ofLONGTEXT
, and the hidden generated column thus is assigned the same data type.MySQL cannot index
LONGTEXT
columns specified without a prefix length on the key part, and prefix lengths are not permitted in functional key parts.
To index the JSON
column, you could try using
the CAST()
function as follows:
The hidden generated column is assigned the
VARCHAR(30)
data type, which can
be indexed. But this approach produces a new issue when trying
to use the index:
CAST()
returns a string with the collationutf8mb4_0900_ai_ci
(the server default collation).JSON_UNQUOTE()
returns a string with the collationutf8mb4_bin
(hard coded).
As a result, there is a collation mismatch between the indexed
expression in the preceding table definition and the
WHERE
clause expression in the following
query:
The index is not used because the expressions in the query and
the index differ. To support this kind of scenario for
functional key parts, the optimizer automatically strips
CAST()
when looking for an index
to use, but only if the collation of the
indexed expression matches that of the query expression. For an
index with a functional key part to be used, either of the
following two solutions work (although they differ somewhat in
effect):
Solution 1. Assign the indexed expression the same collation as
JSON_UNQUOTE()
:- data JSON,
- );
- ('{ "name": "james", "salary": 9000 }'),
- ('{ "name": "James", "salary": 10000 }'),
- ('{ "name": "Mary", "salary": 12000 }'),
- ('{ "name": "Peter", "salary": 8000 }');
The
->>
operator is the same asJSON_UNQUOTE(JSON_EXTRACT(...))
, andJSON_UNQUOTE()
returns a string with collationutf8mb4_bin
. The comparison is thus case sensitive, and only one row matches:- +------------------------------------+
- +------------------------------------+
- | {"name": "James", "salary": 10000} |
- +------------------------------------+
Solution 2. Specify the full expression in the query:
- data JSON,
- );
- ('{ "name": "james", "salary": 9000 }'),
- ('{ "name": "James", "salary": 10000 }'),
- ('{ "name": "Mary", "salary": 12000 }'),
- ('{ "name": "Peter", "salary": 8000 }');
CAST()
returns a string with collationutf8mb4_0900_ai_ci
, so the comparison case insensitive and two rows match:- +------------------------------------+
- +------------------------------------+
- | {"name": "james", "salary": 9000} |
- | {"name": "James", "salary": 10000} |
- +------------------------------------+
Be aware that although the the optimizer supports automatically
stripping CAST()
with indexed
generated columns, the following approach does not work because
it produces a different result with and without an index
(Bug#27337092):
- data JSON,
- );
- Query OK, 0 rows affected, 1 warning (0.03 sec)
- Query OK, 2 rows affected, 1 warning (0.01 sec)
- +-------------------+---------------+
- +-------------------+---------------+
- | {"name": "James"} | James |
- +-------------------+---------------+
- Query OK, 0 rows affected, 1 warning (0.03 sec)
- +-------------------+---------------+
- +-------------------+---------------+
- | {"name": "james"} | james |
- | {"name": "James"} | James |
- +-------------------+---------------+
A UNIQUE
index creates a constraint such that
all values in the index must be distinct. An error occurs if you
try to add a new row with a key value that matches an existing
row. If you specify a prefix value for a column in a
UNIQUE
index, the column values must be
unique within the prefix length. A UNIQUE
index permits multiple NULL
values for
columns that can contain NULL
.
If a table has a PRIMARY KEY
or
UNIQUE NOT NULL
index that consists of a
single column that has an integer type, you can use
_rowid
to refer to the indexed column in
SELECT
statements, as follows:
_rowid
refers to thePRIMARY KEY
column if there is aPRIMARY KEY
consisting of a single integer column. If there is aPRIMARY KEY
but it does not consist of a single integer column,_rowid
cannot be used.Otherwise,
_rowid
refers to the column in the firstUNIQUE NOT NULL
index if that index consists of a single integer column. If the firstUNIQUE NOT NULL
index does not consist of a single integer column,_rowid
cannot be used.
FULLTEXT
indexes are supported only for
InnoDB
and
MyISAM
tables and can include only
CHAR
,
VARCHAR
, and
TEXT
columns. Indexing always
happens over the entire column; column prefix indexing is not
supported and any prefix length is ignored if specified. See
Section 12.9, “Full-Text Search Functions”, for details of operation.
The MyISAM
,
InnoDB
,
NDB
, and
ARCHIVE
storage engines support
spatial columns such as POINT
and
GEOMETRY
.
(Section 11.5, “Spatial Data Types”, describes the spatial data
types.) However, support for spatial column indexing varies
among engines. Spatial and nonspatial indexes on spatial columns
are available according to the following rules.
Spatial indexes on spatial columns have these characteristics:
Available only for
InnoDB
andMyISAM
tables. SpecifyingSPATIAL INDEX
for other storage engines results in an error.As of MySQL 8.0.12, an index on a spatial column must be a
SPATIAL
index. TheSPATIAL
keyword is thus optional but implicit for creating an index on a spatial column.Available for single spatial columns only. A spatial index cannot be created over multiple spatial columns.
Indexed columns must be
NOT NULL
.Column prefix lengths are prohibited. The full width of each column is indexed.
Not permitted for a primary key or unique index.
Nonspatial indexes on spatial columns (created with
INDEX
, UNIQUE
, or
PRIMARY KEY
) have these characteristics:
Permitted for any storage engine that supports spatial columns except
ARCHIVE
.Columns can be
NULL
unless the index is a primary key.The index type for a non-
SPATIAL
index depends on the storage engine. Currently, B-tree is used.Permitted for a column that can have
NULL
values only forInnoDB
,MyISAM
, andMEMORY
tables.
Following the key part list, index options can be given. An
index_option
value can be any of the
following:
KEY_BLOCK_SIZE [=]
value
For
MyISAM
tables,KEY_BLOCK_SIZE
optionally specifies the size in bytes to use for index key blocks. The value is treated as a hint; a different size could be used if necessary. AKEY_BLOCK_SIZE
value specified for an individual index definition overrides a table-levelKEY_BLOCK_SIZE
value.KEY_BLOCK_SIZE
is not supported at the index level forInnoDB
tables. See Section 13.1.20, “CREATE TABLE Syntax”.index_type
Some storage engines permit you to specify an index type when creating an index. For example:
Table 13.1, “Index Types Per Storage Engine” shows the permissible index type values supported by different storage engines. Where multiple index types are listed, the first one is the default when no index type specifier is given. Storage engines not listed in the table do not support an
index_type
clause in index definitions.The
index_type
clause cannot be used forFULLTEXT INDEX
or (prior to MySQL 8.0.12)SPATIAL INDEX
specifications. Full-text index implementation is storage engine dependent. Spatial indexes are implemented as R-tree indexes.If you specify an index type that is not valid for a given storage engine, but another index type is available that the engine can use without affecting query results, the engine uses the available type. The parser recognizes
RTREE
as a type name. As of MySQL 8.0.12, this is permitted only forSPATIAL
indexes. Prior to 8.0.12,RTREE
cannot be specified for any storage engine.BTREE
indexes are implemented by theNDB
storage engine as T-tree indexes.NoteFor indexes on
NDB
table columns, theUSING
option can be specified only for a unique index or primary key.USING HASH
prevents the creation of an ordered index; otherwise, creating a unique index or primary key on anNDB
table automatically results in the creation of both an ordered index and a hash index, each of which indexes the same set of columns.For unique indexes that include one or more
NULL
columns of anNDB
table, the hash index can be used only to look up literal values, which means thatIS [NOT] NULL
conditions require a full scan of the table. One workaround is to make sure that a unique index using one or moreNULL
columns on such a table is always created in such a way that it includes the ordered index; that is, avoid employingUSING HASH
when creating the index.If you specify an index type that is not valid for a given storage engine, but another index type is available that the engine can use without affecting query results, the engine uses the available type. The parser recognizes
RTREE
as a type name, but currently this cannot be specified for any storage engine.NoteUse of the
index_type
option before theON
clause is deprecated; support for use of the option in this position will be removed in a future MySQL release. If antbl_name
index_type
option is given in both the earlier and later positions, the final option applies.TYPE
is recognized as a synonym fortype_name
USING
. However,type_name
USING
is the preferred form.The following tables show index characteristics for the storage engines that support the
index_type
option.Table 13.2 InnoDB Storage Engine Index Characteristics
Index Class Index Type Stores NULL VALUES Permits Multiple NULL Values IS NULL Scan Type IS NOT NULL Scan Type Primary key BTREE
No No N/A N/A Unique BTREE
Yes Yes Index Index Key BTREE
Yes Yes Index Index FULLTEXT
N/A Yes Yes Table Table SPATIAL
N/A No No N/A N/A
Table 13.3 MyISAM Storage Engine Index Characteristics
Index Class Index Type Stores NULL VALUES Permits Multiple NULL Values IS NULL Scan Type IS NOT NULL Scan Type Primary key BTREE
No No N/A N/A Unique BTREE
Yes Yes Index Index Key BTREE
Yes Yes Index Index FULLTEXT
N/A Yes Yes Table Table SPATIAL
N/A No No N/A N/A
Table 13.4 MEMORY Storage Engine Index Characteristics
Index Class Index Type Stores NULL VALUES Permits Multiple NULL Values IS NULL Scan Type IS NOT NULL Scan Type Primary key BTREE
No No N/A N/A Unique BTREE
Yes Yes Index Index Key BTREE
Yes Yes Index Index Primary key HASH
No No N/A N/A Unique HASH
Yes Yes Index Index Key HASH
Yes Yes Index Index
Table 13.5 NDB Storage Engine Index Characteristics
Index Class Index Type Stores NULL VALUES Permits Multiple NULL Values IS NULL Scan Type IS NOT NULL Scan Type Primary key BTREE
No No Index Index Unique BTREE
Yes Yes Index Index Key BTREE
Yes Yes Index Index Primary key HASH
No No Table (see note 1) Table (see note 1) Unique HASH
Yes Yes Table (see note 1) Table (see note 1) Key HASH
Yes Yes Table (see note 1) Table (see note 1) Table note:
1.
USING HASH
prevents creation of an implicit ordered index.WITH PARSER
parser_name
This option can be used only with
FULLTEXT
indexes. It associates a parser plugin with the index if full-text indexing and searching operations need special handling.InnoDB
andMyISAM
support full-text parser plugins. See Full-Text Parser Plugins and Section 29.2.4.4, “Writing Full-Text Parser Plugins” for more information.COMMENT '
string
'Index definitions can include an optional comment of up to 1024 characters.
The
MERGE_THRESHOLD
for index pages can be configured for individual indexes using theindex_option
COMMENT
clause of theCREATE INDEX
statement. For example:If the page-full percentage for an index page falls below the
MERGE_THRESHOLD
value when a row is deleted or when a row is shortened by an update operation,InnoDB
attempts to merge the index page with a neighboring index page. The defaultMERGE_THRESHOLD
value is 50, which is the previously hardcoded value.MERGE_THRESHOLD
can also be defined at the index level and table level usingCREATE TABLE
andALTER TABLE
statements. For more information, see Section 15.8.11, “Configuring the Merge Threshold for Index Pages”.VISIBLE
,INVISIBLE
Specify index visibility. Indexes are visible by default. An invisible index is not used by the optimizer. Specification of index visibility applies to indexes other than primary keys (either explicit or implicit). For more information, see Section 8.3.12, “Invisible Indexes”.
ALGORITHM
and LOCK
clauses
may be given to influence the table copying method and level of
concurrency for reading and writing the table while its indexes
are being modified. They have the same meaning as for the
ALTER TABLE
statement. For more
information, see Section 13.1.9, “ALTER TABLE Syntax”
NDB Cluster supports online operations using the same
ALGORITHM=INPLACE
syntax used with the
standard MySQL Server. See
Section 22.5.14, “Online Operations with ALTER TABLE in NDB Cluster”, for more
information.
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-index.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
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.