MySQL索引
建测试表
CREATE TABLE `t` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `a` varchar(255) DEFAULT NULL, `b` varchar(255) DEFAULT NULL, `c` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`), KEY `a_b` (`a`,`b`) ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=latin1;
ALTER TABLE tbl_name ADD PRIMARY KEY (column_list): 该语句添加一个主键,这意味着索引值必须是唯一的,且不能为NULL。
ALTER TABLE tbl_name ADD UNIQUE index_name (column_list): 这条语句创建索引的值必须是唯一的(除了NULL外,NULL可能会出现多次)。
ALTER TABLE tbl_name ADD INDEX index_name (column_list): 添加普通索引,索引值可出现多次
添加联合索引 a_b
#EXPLAIN SELECT * FROM t WHERE id = 1 #EXPLAIN SELECT * FROM t WHERE a = 3 #EXPLAIN SELECT * FROM t WHERE a = 3 AND b =4 #EXPLAIN SELECT * FROM t WHERE a = 3 AND c =5 EXPLAIN SELECT * FROM t WHERE a = 3 GROUP BY id
possible_keys: PRIMARY,a_b
key: PRIMARY
-
possible_keys: 此次查询中可能选用的索引
-
key: 此次查询中确切使用到的索引
14.6.2.1 Clustered and Secondary Indexes
Every InnoDB
table has a special index called the clustered index where the data for the rows is stored. Typically, the clustered index is synonymous with theprimary key. To get the best performance from queries, inserts, and other database operations, you must understand how InnoDB
uses the clustered index to optimize the most common lookup and DML operations for each table.
-
When you define a
PRIMARY KEY
on your table,InnoDB
uses it as the clustered index. Define a primary key for each table that you create. If there is no logical unique and non-null column or set of columns, add a new auto-increment column, whose values are filled in automatically. -
If you do not define a
PRIMARY KEY
for your table, MySQL locates the firstUNIQUE
index where all the key columns areNOT NULL
andInnoDB
uses it as the clustered index. -
If the table has no
PRIMARY KEY
or suitableUNIQUE
index,InnoDB
internally generates a hidden clustered index namedGEN_CLUST_INDEX
on a synthetic column containing row ID values. The rows are ordered by the ID thatInnoDB
assigns to the rows in such a table. The row ID is a 6-byte field that increases monotonically as new rows are inserted. Thus, the rows ordered by the row ID are physically in insertion order.
Accessing a row through the clustered index is fast because the index search leads directly to the page with all the row data. If a table is large, the clustered index architecture often saves a disk I/O operation when compared to storage organizations that store row data using a different page from the index record.
All indexes other than the clustered index are known as secondary indexes. In InnoDB
, each record in a secondary index contains the primary key columns for the row, as well as the columns specified for the secondary index. InnoDB
uses this primary key value to search for the row in the clustered index.
If the primary key is long, the secondary indexes use more space, so it is advantageous to have a short primary key.
For guidelines to take advantage of InnoDB
clustered and secondary indexes, see Section 8.3, “Optimization and Indexes”.
===============================================================================================================
8.3.1 How MySQL Uses Indexes
Indexes are used to find rows with specific column values quickly. Without an index, MySQL must begin with the first row and then read through the entire table to find the relevant rows. The larger the table, the more this costs. If the table has an index for the columns in question, MySQL can quickly determine the position to seek to in the middle of the data file without having to look at all the data. This is much faster than reading every row sequentially.
Most MySQL indexes (PRIMARY KEY
, UNIQUE
, INDEX
, and FULLTEXT
) are stored in B-trees. Exceptions: Indexes on spatial data types use R-trees; MEMORY
tables also support hash indexes; InnoDB
uses inverted lists for FULLTEXT
indexes.
In general, indexes are used as described in the following discussion. Characteristics specific to hash indexes (as used in MEMORY
tables) are described inSection 8.3.8, “Comparison of B-Tree and Hash Indexes”.
MySQL uses indexes for these operations:
-
To find the rows matching a
WHERE
clause quickly. -
To eliminate rows from consideration. If there is a choice between multiple indexes, MySQL normally uses the index that finds the smallest number of rows (the most selective index).
-
If the table has a multiple-column index, any leftmost prefix of the index can be used by the optimizer to look up rows. For example, if you have a three-column index on
(col1, col2, col3)
, you have indexed search capabilities on(col1)
,(col1, col2)
, and(col1, col2, col3)
. For more information, see Section 8.3.5, “Multiple-Column Indexes”. -
To retrieve rows from other tables when performing joins. MySQL can use indexes on columns more efficiently if they are declared as the same type and size. In this context,
VARCHAR
andCHAR
are considered the same if they are declared as the same size. For example,VARCHAR(10)
andCHAR(10)
are the same size, butVARCHAR(10)
andCHAR(15)
are not.For comparisons between nonbinary string columns, both columns should use the same character set. For example, comparing a
utf8
column with alatin1
column precludes use of an index.Comparison of dissimilar columns (comparing a string column to a temporal or numeric column, for example) may prevent use of indexes if values cannot be compared directly without conversion. For a given value such as
1
in the numeric column, it might compare equal to any number of values in the string column such as'1'
,' 1'
,'00001'
, or'01.e1'
. This rules out use of any indexes for the string column. -
To find the
MIN()
orMAX()
value for a specific indexed columnkey_col
. This is optimized by a preprocessor that checks whether you are usingWHERE
on all key parts that occur beforekey_part_N
=constant
key_col
in the index. In this case, MySQL does a single key lookup for eachMIN()
orMAX()
expression and replaces it with a constant. If all expressions are replaced with constants, the query returns at once. For example:SELECT MIN(key_part2),MAX(key_part2) FROM tbl_name WHERE key_part1=10;
-
To sort or group a table if the sorting or grouping is done on a leftmost prefix of a usable index (for example,
ORDER BY
). If all key parts are followed bykey_part1
,key_part2
DESC
, the key is read in reverse order. See Section 8.2.1.14, “ORDER BY Optimization”, and Section 8.2.1.15, “GROUP BY Optimization”. -
In some cases, a query can be optimized to retrieve values without consulting the data rows. (An index that provides all the necessary results for a query is called a covering index.) If a query uses from a table only columns that are included in some index, the selected values can be retrieved from the index tree for greater speed:
SELECT key_part3 FROM tbl_name WHERE key_part1=1
Indexes are less important for queries on small tables, or big tables where report queries process most or all of the rows. When a query needs to access most of the rows, reading sequentially is faster than working through an index. Sequential reads minimize disk seeks, even if not all the rows are needed for the query. See Section 8.2.1.20, “Avoiding Full Table Scans” for details.
===============================================================================================================
Use of Indexes to Satisfy ORDER BY
In some cases, MySQL may use an index to satisfy an ORDER BY
clause and avoid the extra sorting involved in performing a filesort
operation.
The index may also be used even if the ORDER BY
does not match the index exactly, as long as all unused portions of the index and all extra ORDER BY
columns are constants in the WHERE
clause. If the index does not contain all columns accessed by the query, the index is used only if index access is cheaper than other access methods.
Assuming that there is an index on (
, the following queries may use the index to resolve the key_part1
, key_part2
)ORDER BY
part. Whether the optimizer actually does so depends on whether reading the index is more efficient than a table scan if columns not in the index must also be read.
-
In this query, the index on
(
enables the optimizer to avoid sorting:key_part1
,key_part2
)SELECT * FROM t1 ORDER BY key_part1, key_part2;
However, the query uses
SELECT *
, which may select more columns thankey_part1
andkey_part2
. In that case, scanning an entire index and looking up table rows to find columns not in the index may be more expensive than scanning the table and sorting the results. If so, the optimizer probably will not use the index. IfSELECT *
selects only the index columns, the index will be used and sorting avoided.If
t1
is anInnoDB
table, the table primary key is implicitly part of the index, and the index can be used to resolve theORDER BY
for this query:SELECT pk, key_part1, key_part2 FROM t1 ORDER BY key_part1, key_part2;
-
In this query,
key_part1
is constant, so all rows accessed through the index are inkey_part2
order, and an index on(
avoids sorting if thekey_part1
,key_part2
)WHERE
clause is selective enough to make an index range scan cheaper than a table scan:SELECT * FROM t1 WHERE key_part1 = constant ORDER BY key_part2;
-
In the next two queries, whether the index is used is similar to the same queries without
DESC
shown previously:SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 DESC; SELECT * FROM t1 WHERE key_part1 = constant ORDER BY key_part2 DESC;
-
In the next two queries,
key_part1
is compared to a constant. The index will be used if theWHERE
clause is selective enough to make an index range scan cheaper than a table scan:SELECT * FROM t1 WHERE key_part1 > constant ORDER BY key_part1 ASC; SELECT * FROM t1 WHERE key_part1 < constant ORDER BY key_part1 DESC;
-
In the next query, the
ORDER BY
does not namekey_part1
, but all rows selected have a constantkey_part1
value, so the index can still be used:SELECT * FROM t1 WHERE key_part1 = constant1 AND key_part2 > constant2 ORDER BY key_part2;
参考:
https://dev.mysql.com/doc/refman/5.7/en/innodb-index-types.html
https://dev.mysql.com/doc/refman/5.7/en/mysql-indexes.html
https://dev.mysql.com/doc/refman/5.7/en/order-by-optimization.html