1. 创建索引的语法
单列索引语法
1 2 3 4 |
ALTER TABLE <table> ADD PRIMARY KEY [index-name] (<column>); # 创建主码索引 ALTER TABLE <table> ADD [UNIQUE] KEY|INDEX [index-name] (<column>); #创建非主码索引,KEY和INDEX关键字可以互换 |
多列索引语法
1 2 |
ALTER TABLE <table> ADD PRIMARY KEY [index-name] (,,...) ; ALTER TABLE <table> ADD [UNIQUE] KEY|INDEX [index-name] (,,...); |
2. 索引的基数
当查询使用不止一个索引的时候,mysql会找到一个最高效的索引。
举例说明:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
mysql> explain select * from artist where type='Band' and founded=1980\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: artist type: index_merge possible_keys: type,founded key: founded,type key_len: 2,1 ref: NULL rows: 385 Extra: Using intersect(founded,type); Using where 1 row in set (0.05 sec) |
在上面的例子中,mysql必须在possible_keys中,做出选择,可以看到,相比type,founded是更高效的索引。我们可以使用索引基数来确定最佳索引。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
mysql> show index from artist\G ….. *************************** 3. row *************************** Table: artist Non_unique: 1 Key_name: type Seq_in_index: 1 Column_name: type Collation: A Cardinality: 9 Sub_part: NULL Packed: NULL Null: Index_type: BTREE Comment: *************************** 4. row *************************** Table: artist Non_unique: 1 Key_name: founded Seq_in_index: 1 Column_name: founded Collation: A Cardinality: 212 Sub_part: NULL Packed: NULL Null: YES Index_type: BTREE Comment: |
从上面的信息中,可以看到founded有更高的索引基数,Cardinality值最大。索引基数可以通过公式:
(索引的唯一性数量/索引的总行数) 来计算。理想情况下,值为1,比如主键索引。
尽管索引基数是唯一性的一个重要指标,但Mysql也会参考有关唯一值的范围和容量等统计信息。有时需要select count(*) 来确定最佳索引。
3. 如果查找的词是以通配符开头,则mysql不会使用索引。
举例说明:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
mysql> explain select * from artist where name like '%Queen%'\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: artist type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 583131 Extra: Using where 1 row in set (0.10 sec) |
如果你需要经常查询一个以通配符开头的查询,常用的方法是在数据库中保存需要查询的值的反序值。例如,假设你查找所有.com结尾的电子邮箱地址,当搜索email like ‘%.com’ 是不会用到索引的。但是,而搜索reverse_email like REVERSE(‘%.com’) 就可以使用定在在reverse_email上面的索引。
4. mysql不支持基于索引的函数。
举例说明:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
mysql> explain select * from artist where UPPER(name) = UPPER('Queen')\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: artist type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 583131 Extra: Using where 1 row in set (0.06 sec) |
因为使用了name列的UPPER函数,索引不会应该name索引。
5. 删除重复索引
任何包含在其他索引的最左边的索引都是重复索引。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Table | Create Table | album | CREATE TABLE `album` ( `album_id` int(10) unsigned NOT NULL, `artist_id` int(10) unsigned NOT NULL, `album_type_id` int(10) unsigned NOT NULL, `name` varchar(255) NOT NULL, `first_released` year(4) NOT NULL, `country_id` smallint(5) unsigned DEFAULT NULL, PRIMARY KEY (`album_id`), KEY `name` (`name`), KEY `artist_id` (`artist_id`), KEY `album_type_id` (`album_type_id`), KEY `country_id` (`country_id`), KEY `m2` (`country_id`,`album_type_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 | |
从上面看出,country_id就是重复索引,因为已经存在m2索引。我们再来看以下的语句。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
mysql> explain select * from album where country_id=112\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: album type: ref possible_keys: country_id,m2 key: country_id key_len: 3 ref: const rows: 11 Extra: Using where 1 row in set (0.34 sec) mysql> explain select * from album use index (m2) where country_id=112\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: album type: ref possible_keys: m2 key: m2 key_len: 3 ref: const rows: 11 Extra: Using where 1 row in set (0.03 sec) |
可以看到使用索引country_id和m2效果是一样的,影响的行数都是11。use index是索引提示的语法,还可以用到的关键字是ignore和force。具体的语法如下:
1 2 3 |
USE {INDEX | KEY} [FOR {JOIN | GROUP BY | ORDER BY}] ([index_list]) IGNORE {INDEX | KEY} [FOR {JOIN | GROUP BY | ORDER BY}] ([index_list]) FORCE {INDEX | KEY} [FOR {JOIN | GROUP BY | ORDER BY}] ([index_list]) |
6. 在InnoDB中,主码的值会附加在非主码索引的每个对应的记录的后面,因此没有必要在在非主码索引中指定主码。这一重要特性意味着InnoDB中的所有非主码索引都隐含有主码列了。
7. 覆盖索引
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
mysql> alter table artist add index (founded); Query OK, 0 rows affected (1.17 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> explain select artist_id, name, founded from artist where founded = 1969\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: artist type: ref possible_keys: founded key: founded key_len: 2 ref: const rows: 1036 Extra: Using index condition 1 row in set (0.00 sec) mysql> alter table artist drop index founded, add index founded_name (founded, name); Query OK, 0 rows affected (1.80 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> explain select artist_id, name, founded from artist where founded = 1969\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: artist type: ref possible_keys: founded_name key: founded_name key_len: 2 ref: const rows: 1035 Extra: Using where; Using index 1 row in set (0.00 sec) |
在Extra中显示Using index时,这并不意味着在访问底层表数据时使用到了索引,这表示只有这个索引才是满足查询所要求的。这种索引称为覆盖索引,比如上面的founded_name。
覆盖索引得名于它满足了查询中给定表用到的所有的列。想要创建一个覆盖索引,这个索引必须包含指定表上包括WHERE语句,ORDER BY语句,GROUP BY语句以及SELECT语句中的所有列。
不要在sql查询中使用select * 。如果在select指定真正用到的列,那么就可以创建合适的索引提高性能。
8.局部索引
如果MySQL需要获取大量行中的更多列的数据,那么创建具有更小行宽度的小型索引会更加有效。
1 2 3 |
mysql> alter table artist add index (name(20)); Query OK, 0 rows affected (1.63 sec) Records: 0 Duplicates: 0 Warnings: 0 |
顶一下