zoukankan      html  css  js  c++  java
  • 索引及其底层原理

    一:索引基本描述

    索引的定义:

    MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构。

    数据库索引就像是一本书的目录一样,使用它可以让你在数据库里搜索查询的速度大大提升。而我们使用索引的目的就是,加快表中的查找和排序。

    使用索引的优点就是:
    提高数据的搜索速度
     加快表与表之间的连接速度
     在信息检索过程中,若使用分组及排序子句进行时,通过建立索引能有效的减少检索过程中所需的分组及排序时间,提高检索效率。
    使用索引的缺点就是:
    在我们建立数据库的时候,需要花费的时间去建立和维护索引,而且随着数据量的增加,需要维护它的时间也会增加。
    在创建索引的时候会占用存储空间。
    在我们需要修改表中的数据时,索引还需要进行动态的维护,所以对数据库的维护带来了一定的麻烦。
     
    索引分类:
    唯一索引:在创建唯一索引时要不能给具有相同的索引值。
    主键索引:在我们给一个字段设置主键的时候,它就会自动创建主键索引,用来确保每一个值都是唯一的。
    聚集索引:我们在表中添加数据的顺序,与我们创建的索引键值相同,而且一个表中只能有一个聚集索引。
    普通索引:它的结构主要以B+树和哈希索引为主,主要是对数据表中的数据进行精确查找。
    全文索引:它的作用是搜索数据表中的字段是不是包含我们搜索的关键字,就像搜索引擎中的模糊查询。
    二:索引命令
    1.创建索引:
    在创建SQL时指定字段创建索引index(id),指对id字段添加索引  eg:create table test3(id int, name varchar(5),age int, index(name));
    1.1.在已存在的表中添加索引
     1.1.1、create [unique|fulltext|spatial] index 索引名 on 表名(属性名);
     eg:create index idx_age on test3(age)
      1.1.2、       alter table 表名 add  [unique|fulltext|spatial] index 索引名 (属性);
     eg:alter table test3 add index idx_id_name(id,name);
    2.展示索引
    show create table +table_name
     
    注:Sid和Sage的属性之前创建的
    其中:KEY 后即为该表中的索引 展示的格式为KEY  索引名(索引对应的字段)
    3  删除索引
    drop index 索引名 on 表名;
     eg:drop index idx_age on test3;

     4、索引的执行过程分析

    在test3表中查询数据
    mysql> select *from student;
    +-----+-------+------+------+
    | Sid | Sname | Sage | Ssex |
    +-----+-------+------+------+
    |   1 | zha   |   20 | n    |
    |   2 | w     |   22 | n    |
    |   3 | li    |   21 | w    |
    |   4 | sun   |   30 | n    |
    +-----+-------+------+------+
    4 rows in set (0.00 sec)

    mysql> select *from student where Sname='w';
    +-----+-------+------+------+
    | Sid | Sname | Sage | Ssex |
    +-----+-------+------+------+
    |   2 | w     |   22 | n    |
    +-----+-------+------+------+
    1 row in set (0.00 sec)
     
    分析SQL执行过程:使用explain 关键字添加在select操作之前,G使显示结果标准化;
     
    当前查询操作没有匹配到索引,影响的数据行数是4,即表中所有的数据,
    若表中数据在成千上万的数据,级该查询操作会影响上万条数据,效率比较低
     
    通过explain分析:当前执行中possible_keys: idx_name可能会使用到idx_name索引,
    key: idx_name在实际使用过程中用到了idx_name索引,整个查询影响了一行数据,
    若查询表中存在上万的数据量,使用索引可以大大提高查询效率 

     使用索引之后(影响行数也变成了一行,根据索引搜索):

     联合索引:可以创建两个联合索引

     但是只可以命中第一个索引

     因此我们在创建复合索引时应该将最常用作限制条件的列放在最左边,依次递减。

    设计好MySql的索引可以让你的数据库飞起来,大大的提高数据库效率。设计MySql索引的时候有一下几点注意:

    1,创建索引

    对于查询占主要的应用来说,索引显得尤为重要。很多时候性能问题很简单的就是因为我们忘了添加索引而造成的,或者说没有添加更为有效的索引导致。如果不加

    索引的话,那么查找任何哪怕只是一条特定的数据都会进行一次全表扫描,如果一张表的数据量很大而符合条件的结果又很少,那么不加索引会引起致命的性能下降。
    但是也不是什么情况都非得建索引不可,比如性别可能就只有两个值,建索引不仅没什么优势,还会影响到更新速度,这被称为过度索引。

    2,复合索引

    比如有一条语句是这样的:select * from users where area=’beijing’ and age=22;

    如果我们是在area和age上分别创建单个索引的话,由于mysql查询每次只能使用一个索引,所以虽然这样已经相对不做索引时全表扫描提高了很多效

    率,但是如果在area、age两列上创建复合索引的话将带来更高的效率。如果我们创建了(area, age,salary)的复合索引,那么其实相当于创建了(area,age,salary)、(area,age)、(area)三个索引,这被称为最佳左前缀特性。
    因此我们在创建复合索引时应该将最常用作限制条件的列放在最左边,依次递减。

    3,索引不会包含有NULL值的列

    只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为NULL。

    4,使用短索引

    对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的 列,如果在前10 个或20 个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。

    5,排序的索引问题

    mysql查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引

    6,like语句操作

    一般情况下不鼓励使用like操作,如果非使用不可,如何使用也是一个问题。like “%aaa%” 不会使用索引而like “aaa%”可以使用索引。

    7,不使用NOT IN和操作

    NOT IN和操作都不会使用索引将进行全表扫描。NOT IN可以NOT EXISTS代替

     三:索引底层原理

     (借鉴文章:https://www.cnblogs.com/hollischuang/p/11987069.html

    1.MYSQL主要哪两种数据结构呢以及相关问题?
    两种索引,一种是B树索引,一种是哈希表索引,这两种索引的查询效率是比较高的
    我们使用的是InnoDB引擎,默认的是B+树
    MYSQL InnoDB存储引擎,基于B树(实际MYSQL采用的是B+树)的索引结构。
    B树是一种m阶平衡树,叶子节点都在同一层,由于每一个节点存储的数据量比较大,索引整个B树的层数是非常低的,基本上不超过三层。
    由于磁盘的读取也是按block块操作的(内存是按page页面操作的),位于同一个磁盘块中的数据会被一次性读取出来,而不是需要什么取什么。即使只需要一个字节,磁盘也会从这个位置开始,顺序向后读取一定长度的数据放入内存。这样做的理论依据是计算机科学中著名的局部性原理: 当一个数据被用到时,其附近的数据也通常会马上被使用。因此B-树的节点大小一般设置为和磁盘块大小一致,这样一个B-树节点,
    就可以通过一次磁盘I/O把一个磁盘块的数据全部存储下来,所以当使用B-树存储索引的时候,磁盘I/O的操作次数是最少的(MySQL的读写效率,主要集中在磁盘I/O上)。
     
    哈希索引当然是由哈希表实现的,哈希表对数据并不排序,因此不适合做区间查找,效率非常低,需要搜索整个哈希表结构。
    问题总结(sql关于索引的面试(注:大部分摘自博客  我以为我对Mysql索引很了解,直到遇到了阿里的面试官 ,还有些我不理解,所以问题不全面,可以点击链接查看原文)):
    1问: Hash索引比较起来有什么优缺点吗?
    因为Hash索引底层是哈希表,哈希表是一种以key-value存储数据(集合知识)的结构,所以多个数据在存储关系上是完全没有任何顺序关系的,所以,对于区间查询是无法直接通过索引查询的,就需要全表扫描。所以,哈希索引只适用于等值查询的场景。而B+ Tree是一种多路平衡查询树,所以他的节点是天然有序的(左子节点小于父节点、父节点小于右子节点),所以对于范围查询的时候不需要做全表扫描。

    问:除了上面这个范围查询的,还能说出其他的一些区别吗?(这个题不太了解后百度了一下)

    科普时间:B+ Tree索引和Hash索引区别 哈希索引适合等值查询,但是不无法进行范围查询 哈希索引没办法利用索引完成排序 哈希索引不支持多列联合索引的最左匹配规则 如果有大量重复键值得情况下,哈希索引的效率会很低,因为存在哈希碰撞问题

    2 问:刚刚我们聊到B+ Tree ,那你知道B+ Tree的叶子节点都可以存哪些东西吗?
    InnoDB的B+ Tree可能存储的是整行数据,也有可能是主键的值。
    3 问那这两者有什么区别吗?
    在 InnoDB 里,索引B+ Tree的叶子节点存储了整行数据的是主键索引,也被称之为聚簇索引(聚集索引)。
    而索引B+ Tree的叶子节点存储了主键的值的是非主键索引,也被称之为非聚簇索引
    4 问:那么,聚簇索引和非聚簇索引,在查询数据的时候有区别吗?
    聚簇索引查询会更快?
    5 问:为什么呢?
    因为主键索引树的叶子节点直接就是我们要查询的整行数据了。而非主键索引的叶子节点是主键的值,查到主键的值以后,还需要再通过主键的值再进行一次查询。
     

    上图为MyISAM主键索引的存储结构,我们能看到的不同是

    1、主键索引树的叶子结点的数据区域没有存放实际的数据,存放的是数据记录的地址。
    2、数据的存储不是按主键顺序存放的,按写入的顺序存放。

    存储引擎:
    MySQL最大的特点在于支持插拔式的存储引擎
    MySQL中存储引擎使用比较多的MYISAM,InNoDB,memory存储引擎 

    myisam 引擎 ---- frm(定义的表结构) + myd(表中的数据记录) + myi(表中的索引)   (数据与索引分离)

               不支事物、外键,优势是访问速度快

    innodb 引擎  --- frm(表的创建结构存储) + idb(表中数据和索引的存储)                                    (数据+索引)

              是mysql默认的存储引擎,具有事物特征,支持外键,支持自动增长列

    mermory引擎 访问比较快,将数据存储在内存中,默认采用的是哈希结构存储(不适用于范围查询)一旦数据库关闭,表中的数据就会丢失

     
     

    6 问:你们创建的那么多索引,到底有没有生效,或者说你们的SQL语句有没有使用索引查询你们有统计过吗?

    这个还没有统计过,除非遇到慢SQL的时候我们才会去排查

    7 问:那排查的时候,有什么手段可以知道有没有走索引查询呢?

    可以通过explain查看sql语句的执行计划,通过执行计划来分析索引使用情况

    8 问:那什么情况下会发生明明创建了索引,但是执行的时候并没有通过索引呢? 

    科普时间——查询优化器 一条SQL语句的查询,可以有不同的执行方案,至于最终选择哪种方案,需要通过优化器进行选择,选择执行成本最低的方案。 在一条单表查询语句真正执行之前,MySQL的查询优化器会找出执行该语句所有可能使用的方案,对比之后找出成本最低的方案。这个成本最低的方案就是所谓的执行计划。

    优化过程大致如下: 1、根据搜索条件,找出所有可能使用的索引    2、计算全表扫描的代价

    3、计算使用不同索引执行查询的代价 4、对比各种执行方案的代价,找出成本最低的那一个

    2.下面详细介绍B树、B+树、B-树
    那么MySQL最终为什么要采用B+树存储索引结构呢,那么看看B-树和B+树在存储结构上有什么不同?
    1、B-树的每一个节点,存了关键字和对应的数据地址,而B+树的非叶子节点只存关键字,不存数据地址
    因此B+树的每一个非叶子节点存储的关键字是远远多于B-树的,B+树的叶子节点存放关键字和数据,
    因此,从树的高度上来说,B+树的高度要小于B-树,使用的磁盘I/O次数少,
    因此查询会更快一些。
    2、B-树由于每个节点都存储关键字和数据,因此离根节点进的数据,查询的就快,离根节点远的数据,查询的就慢;
    B+树所有的数据都存在叶子节点上,因此在B+树上搜索关键字,找到对应数据的时间是比较平均的,没有快慢之分。
    3、在B-树上如果做区间查找,遍历的节点是非常多的;B+树所有叶子节点被连接成了有序链表结构,因此做整表遍历和区间查找是非常容易的。

    B树:

     B-tree树即B树,B即Balanced,平衡的意思。因为B树的原英文名称为B-tree,而国内很多人喜欢把B-tree译作B-树,其实,这是个非常不好的直译,很容易让人产生误解。如人们可能会以为B-树是一种树,而B树又是另一种树。而事实上是,B-tree就是指的B树。特此说明。
    先介绍下二叉搜索树
           1.所有非叶子结点至多拥有两个儿子(Left和Right);
           2.所有结点存储一个关键字;
           3.非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树;
    二叉搜索树的搜索,从根结点开始,如果查询的关键字与结点的关键字相等,那么就命中;否则,如果查询关键字比结点关键字小,就进入左儿子;如果比结点关键字大,就进入右儿子;如果左儿子或右儿子的指针为空,则报告找不到相应的关键字;
    B-树:  B-树的搜索,从根结点开始,对结点内的关键字(有序)序列进行二分查找,如果命中则结束,否则进入查询关键字所属范围的儿子结点;重复,直到所对应的儿子指针为空,或已经是叶子结点;

    B-树的特性:

           1.关键字集合分布在整颗树中;

           2.任何一个关键字出现且只出现在一个结点中;

           3.搜索有可能在非叶子结点结束;

           4.其搜索性能等价于在关键字全集内做一次二分查找;

           5.自动层次控制;

    B+树:  B+的搜索与B-树也基本相同,区别是B+树只有达到叶子结点才命中(B-树可以在非叶子结点命中),其性能也等价于在关键字全集做一次二分查找;

      B+的特性:
           1.所有关键字都出现在叶子结点的链表中(稠密索引),且链表中的关键字恰好是有序的;
           2.不可能在非叶子结点命中;
           3.非叶子结点相当于是叶子结点的索引(稀疏索引),叶子结点相当于是存储(关键字)数据的数据层;
           4.更适合文件索引系统;
  • 相关阅读:
    Ubuntu中root用户和user用户的相互切换
    MVCC
    vs2010和C#4.0
    使用命令选项连接到MySQL服务器(参考MySQL官方文档)
    使用外部数据源连接WIN版本的MySQL时,测试连接无法通过
    MySQL学习进阶路线
    解决linux(centos7)重新安装mysql systemctl start mysqld.service时报错
    最最完整的 MySQL 规范都在这了
    Linux性能测试与调优的15条常用命令
    (转载)libevent源码深度剖析二
  • 原文地址:https://www.cnblogs.com/laurarararararara/p/11968305.html
Copyright © 2011-2022 走看看