How to Create Indexes In MySQL
This article descrbes how to create indexes in MySQL using the CREATE INDEX
statement.
Indexes can improve the speed of data retrieval from a table. In a MySQL database, you can add an index to a table using the CREATE INDEX
statement.
For a table with a large number of rows, if it is slow to retrieve data based on a certain query condition, it may be because you have not created an index on the column related to the query condition.
An index is similar to a table of contents in a dictionary. If you want to look up a word in the dictionary, the correct way is to check the table of contents first, and then follow the instructions to find the relevant word on the specified page. Proper indexes can significantly increase the speed of retrieving rows from database tables.
MySQL allows you to create indexes on specified columns in a specified table using the CREATE INDEX
statement.
Introduction
An index is a data structure, such as a B-Tree, that increases the speed of data retrieval from a table, but requires additional writes and storage to maintain it.
The query optimizer can use indexes to quickly locate data without having to scan all rows in the table for a given query.
When you create a table with a primary key or unique key, MySQL automatically creates an PRIMARY
index. This index is called a clustered index .
PRIMARY
indexes are special because the index itself is stored in the same table as the data. A clustered index enforces the order of the rows in the table.
Indexes other than PRIMARY
indexes are called secondary or nonclustered indexes.
MySQL CREATE INDEX
syntax
You should use the following syntax of CREATE INDEX
to add an index to a table:
CREATE [UNIQUE] INDEX index_name
[USING {BTREE | HASH}]
ON table_name (column_list)
[algorithm_option | lock_option];
Explanation:
-
The
UNIQUE
keyword indicates that this index is a unique index. It is optional. -
index_name
is the name of the index. There should not be two indexes with the same name in a table. -
table_name
is the name of the table. -
column_list
is the column names in the table. Multiple column names are separated by commas. -
The
USING
clause specifies the type of index. Possible values:BTREE
,HASH
. It is optional. -
algorithm_option
specifies the algorithm for creating indexes. It uses the following syntax:ALGORITHM [=] {DEFAULT | INPLACE | COPY}
ALGORITHM
clause is optional. Default isINSTANT
.INSTANT
used if not supportedINPLACE
.Using
DEFAULT
and omitting theALGORITHM
clause has the same effect.The following is a description of each algorithm:
COPY
: Operate on the copy of the original table, and copy the table data in the original table to the new table row by row. Concurrent DML is not allowed.INPLACE
: The operation avoids copying table data, but may rebuild the table in-place. Exclusive metadata locks on tables may be briefly held during the preparation and execution phases of an operation. In general, concurrent DML is supported.INSTANT
: The operation only modifies the metadata in the data dictionary. During the execution phase of the operation, an exclusive metadata lock may be briefly held on the table. Table data is unaffected, making operations instantaneous. Concurrent DML is allowed. (introduced in MySQL 8.0.12)
-
lock_option
Specifies the concurrency control strategy for creating indexes. It uses the following syntax:LOCK [=] {DEFAULT | NONE | SHARED | EXCLUSIVE}
LOCK
clause is optional. The following are descriptions of each concurrency strategy:DEFAULT
-
The maximum concurrency level for the given
ALGORITHM
clause (if any) andALTER TABLE
operation: Concurrent reads and writes are allowed, if supported. If not, concurrent reads are allowed (if supported). If not, exclusive access is enforced. NONE
-
Allows concurrent reads and writes if supported. Otherwise, an error will occur.
SHARED
-
If supported, allow concurrent reads but block writes. Writes are blocked even if the storage engine supports concurrent writes for the given
ALGORITHM
clause (if any) and operation.ALTER TABLE
An error occurs if concurrent reads are not supported. EXCLUSIVE
-
Enforce exclusive access. This is done even if the storage engine supports concurrent read/write for the given
ALGORITHM
clause (if any) and operation.ALTER TABLE
Internally in MySQL, CREATE INDEX
statements are mapped to ALTER TABLE ... ADD INDEX ...
statements.
MySQL index types
By default, if you do not specify an index type, MySQL will create a B-Tree index. The following shows the index types allowed for table-based storage engines:
storage engine | allowed index types |
---|---|
InnoDB | BTREE |
MyISAM | BTREE |
MEMORY/HEAP | HASH ,BTREE |
MySQL CREATE INDEX
instance
In the following examples, we use the actor
table from the Sakila sample database for demonstration.
The following statement finds an actor with first name NICK
:
SELECT * FROM sakila.actor WHERE first_name = 'NICK';
Here’s the output:
+----------+------------+-----------+---------------------+
| actor_id | first_name | last_name | last_update |
+----------+------------+-----------+---------------------+
| 2 | NICK | WAHLBERG | 2006-02-15 04:34:33 |
| 44 | NICK | STALLONE | 2006-02-15 04:34:33 |
| 166 | NICK | DEGENERES | 2006-02-15 04:34:33 |
+----------+------------+-----------+---------------------+
You can use EXPLAIN
to view the execution plan of the above SELECT
statement to understand how MySQL executes this query internally, as follows:
EXPLAIN SELECT * FROM sakila.actor WHERE first_name = 'NICK';
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | actor | NULL | ALL | NULL | NULL | NULL | NULL | 201 | 10.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
As you can see, MySQL has to scan the entire table consisting of 201 rows to find a row with a matching condition.
Now, let’s create an index CREATE INDEX
on this first_name
column using the following statement:
CREATE INDEX first_name ON actor(first_name);
Here, we have created an index on the actor
table for the first_name
column with the name first_name
.
To see whether the index was created successfully, use the following SHOW INDEXES
statement display actor
the index of the table, for example:
SHOW INDEXES FROM actor;
Here’s the output:
+-------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| actor | 0 | PRIMARY | 1 | actor_id | A | 201 | NULL | NULL | | BTREE | | | YES | NULL |
| actor | 1 | idx_actor_last_name | 1 | last_name | A | 122 | NULL | NULL | | BTREE | | | YES | NULL |
| actor | 1 | first_name | 1 | first_name | A | 129 | NULL | NULL | | BTREE | | | YES | NULL |
+-------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
Then, execute the above EXPLAIN
statement:
EXPLAIN SELECT * FROM sakila.actor WHERE first_name = 'NICK';
The output is:
+----+-------------+-------+------------+------+---------------+------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------------+---------+-------+------+----------+-------+
| 1 | SIMPLE | actor | NULL | ref | first_name | first_name | 182 | const | 3 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+------------+---------+-------+------+----------+-------+
As you can see, MySQL only needs to locate 3 of the rows from the first_name
indicated index without scanning the entire table.
Conclusion
In MySQL, indexes can improve the efficiency of querying data from tables. You can create indexes for tables using CREATE INDEX
.