MySQL基础知识—索引(未完成)

原理

索引是在数据库表的字段上添加的,是为了提高查询效率存在的一种机制。

索引在MySQL中也叫做键,是存储引擎用于快速找到记录的一种数据结构。

索引对于良好的性能非常关键,尤其是当表中的数据量越来越大时,索引对于性能的影响愈发重要。

索引优化应该是对查询性能优化最有效的手段了。索引能够轻易将查询性能提高好几个数量级。

索引相当于字典的音序表,如果要查某个字,如果不使用音序表,则需要从几百页中逐页去查。

基础

在MySQL中,存储引擎用类似书的索引方法使用索引,其先在索引中找到对应值,然后根据匹配的索引记录找到对应的数据行。假如要运行下面的查询:

mysql> SELECT first_name FROM sakila.actor WHERE actor_id=5;

如果在actor_id列上建有索引,则MySQL将使用该索引找到actor_id为5的行,也就是说,MySQL先在索引上按值进行查找,然后返回所有包含该值的数据行。

索引可以包含一个或多个列的值。如果索引包含多个列,那么列的顺序也十分重要,因为MySQL只能高效地使用索引的最左前缀列创建一个包含两个列的索引,和创建两个只包含一列的索引是大不相同的。

  • 在MySQL中,主键和有unique约束的字段,会自动添加索引对象
  • 在mysql中,索引是一个单独的对象,不同的存储引擎以不同的形式存在,在MyISAM中,为.MYI文件,在InnoDB中,为tablespace文件,在MEMORY中,被存储在内存中。

索引的类型

索引有很多种类型,可以为不同的场景提供更好的性能。

在MySQL中,索引是在存储引擎层而不是服务器层实现的。所以,并没有统一的索引标准:不同存储引擎的索引的工作方式并不一样,也不是所有的存储引擎都支持所有类型的索引。即使多个存储引擎支持同一种类型的索引,其底层的实现也可能不同。

B-Tree索引

没有特别指明类型的索引,一般都是B-Tree索引。

它使用B-Tree数据结构来存储数据。大多数MySQL存储引擎都支持这种索引。

存储引擎以不同的方式来使用B-Tree索引,性能也各有不同,各有优劣。

  • MyISAM使用前缀压缩技术使得索引更小,通过数据的物理位置引用被索引的行
  • InnoDB使用原数据格式进行存储,根据主键引用被索引的行。

下图展示了B-Tree索引的抽象表示,大致反映了InnoDB索引是如何工作的。

B-Tree索引可以加快访问数据的速度,因为存储引擎不再需要进行全表扫描来获取数据,而是从索引的根节点开始进行搜索。

根节点的槽中存放了指向子节点的指针,存储引擎根据这些指针向下层查找。通过比较节点页的值和要查找的值可以找到合适的指针进入下层子节点,这些指针实际上定义了子节点页中值的上限和下限。最终存储引擎要么是找到对应的值,要么该记录不存在。

在叶子节点中,指针指向的是被索引的数据,而不是其他节点页。

B-Tree对索引列是顺序组织存储的,很适合查找范围数据。

示例

假设有如下数据表:

CREATE TABLE People (
   last_name varchar(50)    not null,
   first_name varchar(50)   not null,
   dob date                 not null,
   gender enum('m', 'f')  not null,
   key(last_name, first_name, dob)
);

对于表中的每一行数据,索引中包含了last_name、frst_name和dob列的值,下图显示了该索引是如何组织数据的存储的。

在上面图中,索引对多个值进行排序的依据是CREATE TABLE语句中定义索引时列的顺序,上面最后两个条目,两个人的姓和名都一样,则根据出生日期来排列顺序。

可使用B-Tree索引的查询类型

全值匹配

全值匹配指的是和索引中的所有列进行匹配,例如前面提到的索引可用于查找姓名为Cuba Allen、出生于1960-01-01的人。

匹配最左前缀

前面提到的索引可用于查找所有姓为Allen的人,即只使用索引的第一列。

匹配列前缀

也可以只匹配某一列的值的开头部分。例如前面提到的索引可用于查找所有以J开头的姓的人。这里也只使用了索引的第一列。

匹配范围值

例如前面提到的索引可用于查找姓在Allen和Barrymore之间的人。这里也只使用了索引的第一列。

精确匹配某一列并范围匹配另外一列

前面提到的索引也可用于查找所有姓为Allen,并且名字是字母K开头(比如Kim、Karl等)的人。即第一列last_name全匹配,第二列frst_name范围匹配。

只访问索引的查询

B-Tree通常可以支持“只访问索引的查询”,即查询只需要访问索引,而无须访问数据行。后面我们将单独讨论这种“覆盖索引”的优化。

注意

1、如果不是按照索引的最左列开始查找,则无法使用索引。【例如上面例子中的索引无法用于查找名字为Bill的人,也无法查找某个特定生日的人,因为这两列都不是最左数据列。最左数据列是姓氏。】

2、不能跳过索引中的列。【前面所述的索引无法用于查找姓为Smith并且在某个特定日期出生的人。如果不指定名(first_name),则MySQL只能使用索引的第一列。】

3、如果查询中某个列的范围查询,则其右边所有列都无法使用索引优化查找。【例如有查询WHERE last_name='Smith' AND frst_name LIKE 'J%' AND dob='1976-12-23',这个查询只能使用索引的前两列,因为这里LIKE是一个范围条件。如果范围查询列值的数量有限,那么可以通过使用多个等于条件来代替范围条件。】

哈希索引

哈希索引(hash index)基于哈希表实现,只有精确匹配所有列的查询才有效。

对于每一行数据,存储引擎都会对所有的索引列计算一个哈希码(hash code),哈希码是一个较小的值,并且不同键值的行计算出来的哈希码也不一样。哈希索引将所有的哈希码存储在索引中,同时在哈希表中保存指向每个数据行的指针。

在MySQL中,只有Memory引擎显式支持哈希索引。

如果多个列的哈希值相同,索引会以链表的方式存放多个记录指针到同一个哈希条目中。

索引的优点

  • 索引可以让服务器快速地定位到表的指定位置。
  • 索引大大减少了服务器需要扫描的数据量。
  • 索引可以帮助服务器避免排序和临时表。
  • 索引可以将随机I/O变为顺序I/O。

Guess you like

Origin blog.csdn.net/kuangd_1992/article/details/121044246
Recommended