索引的设计和使用(一)

索引是数据库中⽤来提⾼性能的最常⽤⼯具。 
索引类型,并简单介绍了索引的设计原则。在后⾯的优化篇中,将会对索引做更多的 介绍。

1 索引概述

所有MySQL列类型都可以被索引,对相关列使⽤索引是提⾼SELECT操作性能的
最佳途径。根据存储引擎可以定义每个表的最⼤索引数和最⼤索引长度,每种存储引 擎(如 MyISAM、InnoDB、BDB、MEMORY等)对每个表⾄少⽀持16个索引,总索 引长度⾄少为256字节。⼤多数存储引擎有更⾼的限制。

MyISAM和InnoDB存储引擎的表默认创建的都是BTREE索引。MySQL支持对索引字段的前N个字符创建索引。前缀索引 的长度跟存储引擎相关,对于MyISAM存储引擎的表,索引的前缀长度可以达到1000 字节长,⽽对于InnoDB存储引擎的表,索引的前缀长度最长是767字节。请注意前缀 的限制应以字节为单位进⾏测量,⽽CREATE TABLE语句中的前缀长度解释为字符 数。在为使⽤多字节字符集的列指定前缀长度时⼀定要加以考虑。

默认情况下,MEMORY存储引擎使⽤HASH索引,但也⽀持BTREE索引。

2  设计索引的原则

索引的设计可以遵循⼀些已有的原则,创建索引的时候请尽量考虑符合这些原则,便于提升索引的使⽤效率,更⾼效地使⽤索引。

1:最适合索引的列是出现在WHERE⼦句中的列,或连接⼦ 句中指定的列,⽽不是出现在SELECT关键字后的选择列表中的列。

2:使⽤唯⼀索引。考虑某列中值的分布。索引的列的基数越⼤,索引的效果越好。例如,存放出⽣⽇期的列具有 不同值,很容易区分各⾏。⽽⽤来记录性别的列,只含有“M”和“F”,则对此列进⾏索引没有多⼤⽤处,因为不管 搜索哪个值,都会得出⼤约⼀半的⾏。

3:使⽤短索引。如果对字符串列进⾏索引,应该指定⼀个前缀长度,只要有可能就应该这样做。例如,有⼀个 CHAR(200)列,如果在前10个或20个字符内,多数值是唯⼀的,那么就不要对整个列进⾏索引。对前10个或20个字 符进⾏索引能够节省⼤量索引空间,也可能会使查询更快。较⼩的索引涉及的磁盘 IO 较少,较短的值⽐较起来更 快。更为重要的是,对于较短的键值,索引⾼速缓存中的块能容纳更多的键值,因此,MySQL 也可以在内存中容 纳更多的值。这样就增加了找到⾏⽽不⽤读取索引中较多块的可能性。

4:利⽤最左前缀。在创建⼀个n列的索引时,实际是创建了MySQL可利⽤的n个索引。多列索引可起⼏个索引的 作⽤,因为可利⽤索引中最左边的列集来匹配⾏。这样的列集称为最左前缀。

5:不要过度索引。不要以为索引“越多越好”,什么东西都⽤索引是错误的。每个额外的索引都要占⽤额外的磁盘 空间,并降低写操作的性能。在修改表的内容时,索引必须进⾏更新,有时可能需要重构,因此,索引越多,所花 的时间越长。如果有⼀个索引很少利⽤或从不使⽤,那么会不必要地减缓表的修改速度。此外,MySQL 在⽣成⼀ 个执⾏计划时,要考虑各个索引,这也要花费时间。创建多余的索引给查询优化带来了更多的⼯作。索引太多,也 可能会使MySQL选择不到所要使⽤的最好索引。只保持所需的索引有利于查询优化。

6:对于InnoDB存储引擎的表,记录默认会按照⼀定的顺序保存,如果有明确定义的主键,则按照主键顺序保 存。如果没有主键,但是有唯⼀索引,那么就是按照唯⼀索引的顺序保存。如果既没有主键又没有唯⼀索引,那么 表中会⾃动⽣成⼀个内部列,按照这个列的顺序保存。按照主键或者内部列进⾏的访问是最快的,所以InnoDB表 尽量⾃⼰指定主键,当表中同时有⼏个列都是唯⼀的,都可以作为主键的时候,要选择最常作为访问条件的列作为 主键,提⾼查询的效率。另外,还需要注意,InnoDB 表的普通索引都会保存主键的键值,所以主键要尽可能选择 较短的数据类型,可以有效地减少索引的磁盘占⽤,提⾼索引的缓存效果。

3 BTREE索引与HASH索引

MEMORY存储引擎的表可以选择使⽤BTREE索引或者HASH索引,两种不同类型的索引各有其不同的适⽤范围。HASH索引有⼀些重要的特征需要在使⽤的时候特别 注意,如下所⽰。
只⽤于使⽤=或<=>操作符的等式⽐较。优化器不能使⽤HASH索引来加速ORDER   BY操作。

MySQL 不能确定在两个值之间⼤约有多少⾏。如果将⼀个 MyISAM 表改为 HASH索引的MEMORY表,会影 响⼀些查询的执⾏效率。只能使⽤整个关键字来搜索⼀⾏。

 ⽽对于BTREE索引,当使⽤>、<、>=、<=、BETWEEN、!=或者<>,或者LIKE 'pattern'       (其中'pattern'不以通配符开始)操作符时,都可以使⽤相关列上的索引。
下列范围查询适⽤于BTREE索引和HASH索引:

SELECT * FROM t1 WHERE key_col = 1 OR key_col IN (15,18,20);
下列范围查询只适⽤于BTREE索引:
SELECT * FROM t1 WHERE key_col > 1 AND key_col < 10;
SELECT * FROM t1 WHERE key_col LIKE 'ab%' OR key_col BETWEEN 'lisa' AND 'simon';
例如,创建⼀个和city表完全相同的MEMORY存储引擎的表city_memory:
mysql> CREATE TABLE city_memory (
-> city_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
-> city VARCHAR(50) NOT NULL,
-> country_id SMALLINT UNSIGNED NOT NULL,
-> last_update TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE  CURRENT_ TIMESTAMP,
-> PRIMARY KEY (city_id),
-> KEY idx_fk_country_id (country_id)
->  )ENGINE=Memory  DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.03 sec)
mysql> insert into city_memory select * from city; Query OK, 600 rows affected (0.00 sec)
Records: 600 Duplicates: 0 Warnings: 0
当对索引字段进⾏范围查询的时候,只有BTREE索引可以通过索引访问:
mysql> explain SELECT * FROM city WHERE country_id > 1 and country_id < 10 \G
*************************** 1. row *************************** id: 1
select_type: SIMPLE

table: city type: range
possible_keys: idx_fk_country_id key: idx_fk_country_id
key_len: 2 ref: NULL rows: 24
Extra: Using where
1 row in set (0.00 sec)
⽽HASH索引实际上是全表扫描的:
mysql> explain SELECT * FROM city_memory WHERE country_id > 1 and country_id < 10 \G
*************************** 1. row *************************** id: 1
select_type: SIMPLE table: city_memory type: ALL
possible_keys: idx_fk_country_id key: NULL
key_len: NULL ref: NULL rows: 600
Extra: Using where
1 row in set (0.00 sec)
了解了 BTREE 索引和 HASH 索引不同后,当使⽤ MEMORY 表时,如果是默认 创建的HASH  索引,就要注意  SQL  语句的编写,确保可以使⽤上索引,如果⼀定要使
⽤范围查询,那么在创建索引时,就应该选择创建成BTREE索引。 

 

 

你可能感兴趣的:(深入浅出MySQL,MySql基础篇)