3. 索引简介 与 优化分析

索引简介

存储数据之外,数据库还维护了一个满足特定查找的数据结构,这些数据结构以某种方式指向数据,以某种算法去查询这个数据结构,目的就是提高查询效率。

一般我们平常所说的索引,如果可以特别指明,都是指B树结构组织的索引。而索引又分类为:次要索引、覆盖索引、复合索引、前缀索引、唯一索引。

索引优势:

  1. 可以搞数据的检索效率,降低数据库的 IO 成本

索引劣势:

  1. 实际上索引也是维护了一张表,该表保存了主键与索引字段,并指向实体表的记录。所以索引列也是要占用空间的。
  2. 在 insert、update、delete 时候,也需要对应的修改索引。所以会降低写数据的速度

索引操作语法

创建索引

1.添加主键索引
ALTER TABLE table_name ADD PRIMARY KEY (column)

2.添加唯一索引
ALTER TABLE table_name ADD UNIQUE (column)

3.添加全文索引
ALTER TABLE table_name ADD FULLTEXT (column)

4.添加普通索引
ALTER TABLE table_name ADD INDEX index_name (column )

5.添加多列索引
ALTER TABLE table_name ADD INDEX index_name (column1, column2, column3)

  1. create 方式创建普通索引
    CREATE INDEX indexName ON tableName( column );

删除索引

DROP INDEX [indexName] ON tableName

查看索引

SHOW INDEX FROM tableName

索引结构与检索原理

看上图中,一棵B+树,浅蓝色的块我们称之为一个磁盘块,可以看到每个磁盘块包含几个数据项(深蓝色所示)和指针(黄色所示),如磁盘块1包含数据项17和35,包含指针P1、P2、P3。

我如果要找29这个数字,那么从根找,P1表示小与17的,P2表示大于17小与35的,P3表示大于35的,那么往下走,真实的数据存在于叶子节点,也就是第三层,即3、5、9、10、13…依次往右看。假设我要查找非叶子节点(第二层),不存储真实的数据,只存储指引搜索方向的数据项,如17、35并不存在真实的数据表中,也就是相当于一个参考值。如果查找29,但是我们先给参考项,那么根据图示,29在17和35之间,锁定磁盘块1的P2指针,找到指针P2,内存时间非常短,相比磁盘的IO可以忽略不计,那么下来之后,找到磁盘块3,也就是不见得加载磁盘块2,这里就第二次IO了,那么看图,29在26和30之间,那么又指向指针P2,再往下就加载到了磁盘块8的内存,发生第三次IO,同时内存中做二分查找找到29,结束查询,总共三次IO。

看Btree也就是三层楼那么高,也就是尽量把数据横向扩,高度矮比较好,真实的情况是,3层的B+树 可以表示上百万的数据,如果上百万的数据查找只需三次IO,性能提高将是巨大的,如果没有所用,每个数据项都要发生一次IO,那么总共需要上百万次的IO,显然成本非常高。
3. 索引简介 与 优化分析_第1张图片

索引使用

哪些适合使索引

  1. 主键自动建立唯一索引
  2. 频繁作为查询条件的字段应该创建索引
  3. 查询中与其他表关联的字段,外键建立索引
  4. 查询排序的字段
  5. 查询统计或分组字段

哪些情况不适合索引

  1. 频繁更新的字段不适合常见索引,因为每次更细你不单单是更新记录还会更新索引
  2. where 条件用不到的字段不创建索引
  3. 表记录太少。几十条,几百条,没必要。

下面引入一个概念,sql 优化几个概念要明白。

基数

某个列唯一键的数量叫作基数。比如性别列,该列只有男女之分,所以这一列基数是2。主键列的基数等于表的总行数。基数的高低影响列的数据分布。使用如下 sql 查看表中数据分布(摘抄自《SQL优化核心思想》)

select count(distinct owner),count(distinct object_id),count(*) from test;

TEST 表的总行数为72462,而上面sql去重后行数为 29,那么基数就是 29,说明owner列里面有大量重复值。

回表

这先要从InnoDB的索引实现说起,InnoDB有两大类索引:

聚集索引

InnoDB聚集索引的叶子节点存储行记录,因此, InnoDB必须要有,且只有一个聚集索引,
(1)如果表定义了PK,则PK就是聚集索引;
(2)如果表没有定义PK,则第一个not NULL unique列是聚集索引;
(3)否则,InnoDB会创建一个隐藏的row-id作为聚集索引
所以PK查询非常快,直接定位行记录
3. 索引简介 与 优化分析_第2张图片

普通索引

就是我们平时使用 create index… 创建的,这个索引只存储对应叶子节点存储主键值。
3. 索引简介 与 优化分析_第3张图片

假设创建表

 t(id PK, name, sex, flag, index(name)));

id是聚集索引,name是普通索引。

当使用 Select * from table where name = ‘xx’ 时候,会有以下步骤:

  1. 在 name 的中找到存储对应数据的键值对(假设 { name=‘xx’ , id = 1 })
  2. 拿到对应数据的 id 后,再去聚集索引中去查找到指定的物理数据

上面需要扫描2次索引树,这就是所谓的回表查询,先定位主键值,再定位行记录,它的性能较扫一遍索引树更低。所以有些人认为过滤条件使用了索引,SQL优化的不错,这其实是一种错误的认识,使用了索引并不代表查询就最优,可能会造成回表太多造成 IO 贼高。所以在数据

如果要想避免回表,建议使用覆盖索引,将被查询的字段,建立到联合索引里去。

你可能感兴趣的:(mysql)