sql索引及优化

索引:是对数据库表中一列或多列的值进行排序的一种结构,只有当经常查询索引列中的数据时,才需要在表上创建索引。
在这里插入图片描述

一.索引介绍

索引是关系型数据库中给数据库表中一列或者多列的值排序后的储存结构,SQL的主流索引结构有B+树以及Hash结构,聚集索引以及非聚集索引用的是B+树索引.

MySql索引类型有:唯一索引,主键(聚集)索引,非聚集索引,全文索引.

1.1:聚集索引

聚集(clustered)索引,也叫做聚簇索引.

定义:数据行的物理顺序与列值(一般是主键的那一列)的逻辑顺序相同,一个表中只能拥有一个聚集索引.

注意:聚集索引做查询可以直接获取对应的全部列的数据.所以聚集查询较快.

1.2非聚集索引

定义:该索引中索引的逻辑顺序与磁盘上行的物理存储顺序不同,一个表中可以拥有多个非聚集索引.

除了聚集索引以外的索引都是非聚集索引,分成普通索引,唯一索引和全文索引.

注意:非聚集索引查询在索引没覆盖到对应列的时候需要进行二次查询,索引非聚集查询较慢.

1.3 mysql为变量添加索引

1.添加PRIMARY KEY(主键索引)

ALTER TABLE `table_name` ADD PRIMARY KEY ( `column` ) 

2.添加UNIQUE(唯一索引)

ALTER TABLE `table_name` ADD UNIQUE ( `column` ) 

3.添加INDEX(普通索引)

ALTER TABLE `table_name` ADD INDEX index_name ( `column` )

4.添加FULLTEXT(全文索引)

ALTER TABLE `table_name` ADD FULLTEXT ( `column`) 

5.添加多列索引

ALTER TABLE `table_name` ADD INDEX index_name ( `column1`, `column2`, `column3` )

二.BTree树实现索引

  • 先从MySQL的基本存储结构说起
    MySQL的基本存储结构是页(记录都存在页里边):
    InnoDB页结构示意图
  • 各个数据页可以组成一个双向链表
  • 每个数据页中的记录又可以组成一个单向链表
    每个数据页都会为存储在它里边儿的记录生成一个页面目录, 在通过主键查找某条记录的时候可以在页目录中使用二分法快速定位到对应的插槽,然后再遍历该插槽对应的分组中的记录即可快速找到指定的记录
    以其他列(非主键)作为搜索条件:只能从最小记录开始依次遍历单链表中的每条记录。

所以说,如果我们写select * from user where indexname ='xxx’这样没有进行任何优化的sql语句,替换会生成:

1.定位到记录所在的页:需要遍历双向链表,找到所在的页
2.从所在的页面内中查找相应的记录:由于不是根据主键查询,只能遍历所在页面的单链表了

很明显,在数据量很大的情况下这样查找会很慢!这样的时间复杂度为O(n)。

  • 使用索引之后
    索引就是一些什么可以让我们查询速度速度呢?其实就是将无序的数据变成有序(相对):
    要找到id为8的记录简要步骤:
    在这里插入图片描述
    很明显的是:没有用索引我们是需要遍历双向链表来定位对应的页面,现在通过“目录”就可以很快地定位到对应的页面上了!(二分查找,时间复杂度近似为O(logn ))

其实实质上结构就是B +树,B +树作为树的一种实现,能够让我们很快地寻找出对应的记录。

三.建立索引的原则

最左基本原则

MySQL中的索引可以以一定顺序引用多列,这种索引叫作联合索引。如用户表的名称和城市加联合索引就是(name,city),而最左上方原则指的是,如果查询的时候查询条件精确匹配索引的左边连续一列或几列,则此列就可以被用到。如下:

select * from user where name=xx and city=xx ; //可以命中索引
select * from user where name=xx ; // 可以命中索引
select * from user where city=xx ; // 无法命中索引 

这里需要注意的是,查询的时候如果两个条件都用上了,但是顺序不同,如city= xx and name =xx,那么现在的查询引擎会自动优化为匹配联合索引的顺序,这样是能够命中索引的。
由于最左上边的原则,在创建联合索引时,索引分段的顺序需要考虑分段值去重之后的个数,否则的放前面。ORDERBY子句也遵循此规则。

  1. 定义主键的数据列一定要建立索引
  2. 定义有外键的数据列一定要建立索引。
  3. 对于经常查询的数据列最好建立索引。
  4. 对于需要在指定范围内的快速或频繁查询的数据列。
  5. 经常出现在关键字order by、group by、distinct后面的字段,建立索引。如果建立的是复合索引,索引的字段顺序要和这些关键字后面的字段顺序一致,否则索引不会被使用。
  6. 对于那些查询中很少涉及的列,重复值比较多的列不要建立索引。

四.sql索引优化面试题

题目一:
select * from student s where s.stuName in(“张三”,“李四”,“王五”)and s.age>18 and s.sex=‘男’;

思路:

1.肯定要建立二级联合索引:index(stuName,age,sex)

2.这里要优化一下sql语句中的in,改用union all

优化后的sql:
select * from student s where s.stuName=“张三” and s.age>18 and s.sex=‘男’ union all select * from student s where s.stuName=“李四” and s.age>18 and s.sex=‘男’ union all select * from student s where s.stuName=“王五” and s.age>18 and s.sex=‘男’ ;

题目二
sql优化(查询9:1)
1.尽量使用列名(Oracle9i之后, *和列名一样)
在业务密集的SQL当中尽量不采用IN操作符,用EXISTS 方案代替。

2、模糊查询like
关键词%yue%,由于yue前面用到了“%”,因此该查询必然走全表扫描,除非必要,否则不要在关键词前加%,

3 二者都能使用尽量使用where (与having比较)
where 先过滤(数据就少了)在分组

4: 理论上,尽量使用多表连接(join)查询(避免子查询)

相关网址:
https://snailclimb.gitee.io/javaguide/#/docs/database/MySQL%20Index
https://blog.csdn.net/qq_44590469/article/details/96473238

https://blog.csdn.net/tian31233/article/details/52052963?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

发布了11 篇原创文章 · 获赞 7 · 访问量 4015

猜你喜欢

转载自blog.csdn.net/wusimin432503/article/details/104446150