1.索引的本质

索引是帮组MYSQL高效获取数据的排好序的数据结构

二叉树

二叉树是树节点的度不大于2的有序树。它是一种最简单最重要的树。

二叉树的左节点始终小于父节点。二叉树的有节点始终大于等于父节点

对于单边递增的数据,二叉树会变成链表的形式。这个时候查询不会减少次数。所以也不会减少IO次数。这就是MYSQL没有使用二叉树的原因。

java 复制代码
@Data
public class NodeTest {

    int fData;   //数据
    NodeTest leftChild;   //左节点
    NodeTest rightChild;  //右节点

    public NodeTest() {

    }

    public static void main(String[] args) {
        NodeTest nodeTest = new NodeTest();

    }



    static class Tree{
        private NodeTest root;

        public boolean insertNode(NodeTest root1,NodeTest nodeTest){
            if (root == null){
                root = nodeTest;
                return true;
            }else {
                // 代表不为null
                if (root1 == null){
                    root1 = root;
                }
                int fData1 = root1.getFData();
                if (fData1 > nodeTest.getFData()){
                    // 左节点
                    if (root1.getLeftChild() == null){
                        root1.setLeftChild(nodeTest);
                        return true;
                    }else {
                         // 左节点不为null
                        insertNode(root1.getLeftChild(),nodeTest);
                    }
                }else {
                    // 左节点
                    if (root1.getRightChild() == null){
                        root1.setRightChild(nodeTest);
                        return true;
                    }else {
                        // 左节点不为null
                        insertNode(root1.getRightChild(),nodeTest);
                    }
                }
            }
            return false;
        }

        public static void main(String[] args) {
            Tree tree = new Tree();
            NodeTest nodeTest = new NodeTest();
            nodeTest.setFData(3);
            boolean b = tree.insertNode(null, nodeTest);

            NodeTest nodeTest1 = new NodeTest();
            nodeTest1.setFData(5);
            tree.insertNode(null,nodeTest1);

            NodeTest nodeTest2 = new NodeTest();
            nodeTest2.setFData(2);
            tree.insertNode(null,nodeTest2);
            NodeTest nodeTest3 = new NodeTest();
            nodeTest3.setFData(3);
            tree.insertNode(null,nodeTest3);
            System.out.println(b);
        }
    }

}

红黑树

  1. 每个结点不是红色就是黑色
  2. 根节点是黑色的
  3. 如果一个节点是红色的,则它的两个孩子结点是黑色的(不会出现连在一起的红色节点)
  4. 对于每个结点,从该结点到其所有后代叶结点简单路径上,均包含相同数目的黑色结点(在计算一条路径中黑色节点个数的时候要带上叶子节点,因为叶子节点也是黑色的,也就是空节点)。
  5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)(为了保证空树也是红黑树)
  6. 红黑树确保没有一条路径会比其他路径长出俩倍(红黑树前面的性质保证了当前的性质)

虽然红黑树会根据性质做出对应的旋转,能够减少树的层级。但是对MYSQL而言存储的数据都是十万百万级别的。对应的树的层级还是很高。进行的IO次数也是不可避免的。所以MYSQL也没有使用红黑树(java中的Map和Set存储数据时如果一个桶上的数据大于8的时候会把链表转换为红黑树)。

B树

B 树也称 B- 树,它是一颗多路平衡查找树。我们描述一颗B树时需要指定它的阶数,阶数表示了一个结点最多有多少个孩子结点,一般用字母m表示阶数。当m取2时,就是我们常见的二叉搜索树。

一颗m阶的B树定义如下:

1)每个结点最多有m-1个关键字。

2)根结点最少可以只有1个关键字。

3)非根结点至少有 Math.ceil(m/2)-1个关键字。

4)每个结点中的关键字都按照从小到大的顺序排列,每个关键字的左子树中的所有关键字都小于它,而右子树中的所有关键字都大于它。

5)所有叶子结点都位于同一层,或者说根结点到每个叶子结点的长度都相同。

B-树每个节点都可以存储多个数据。而且也有红黑树的旋转属性。所以存储数据相同的情况下B数的层级更小。所以IO次数就会少。但是由于每个节点的数据都会存储真实的数据,真实数据往往比较大。所以导致一层节点存储的数据是有限的。所以MYSQL也没有用B树做为索引的存储结构。会用到下面的B+ 树。

B+ 树

B+ 树是B树的一个变种。B+ 树的非叶子节点不在存储数据。只进行数据索引。叶子节点结构也是有序的。并且每个元素会存储下一个元素的索引和上一个元素的索引。这样就大大增加了每一层非叶子节点存储的数据索引质量了。

假如一个节点能存储16KB、索引占用10b、数据占用1Kb则三层树可以存储多少?

结果\层 B B+
1 16 1600
2 16 * 16 = 256 1600 * 1600 = 2560000
3 256 * 16 = 4096 2560000 * 16 = 40960000

大概算了下发现B+ 比 B多存储了四个量级的数据。所以B+ 树IO次数在大数据两下比B树要小的多。

主键索引和联合索引的区别

  1. 主键索引是聚簇索引、联合索引是非聚簇索引。
  2. 主键索引推荐用int类型并且是自增的(减少B+树的旋转和调整)。并且聚簇索引叶子结点存储的是一条数据的所有值。非聚簇索引存叶子结点存储的是主键id。所以如果使用非聚簇索引查询数据,然后使用select * 还需要获取id数据后进行主键索引树中进行回表查询。所以会浪费一部分时间。
  3. 为啥非聚簇索引不存储一整行数据
    1. 为了保证数据一致性和节省空间。
      1. 因为如果索引都存储所有的数据。那每个索引在数据修改的时候都要更改为最新的数据。这个就无法保证了数据的一致性。
      2. 非聚簇索引不保存全部数据就可以减少很都空间。

索引覆盖

通俗来讲就是在执行某个查询语句时进行,在一个索引树(非聚簇索引)上就能查询到需要的字段、而无需回了,这就是索引覆盖。正确是使用好索引覆盖可以减少sql的执行时间。

比如:

创建一个user表:

sql 复制代码
creat table user(
	id int primary key,
	name varchar(20),
	sex varchar(5)
) engine=innodb;
ALTER TABLE user ADD INDEX index_name (name);: 添加name字段普通索引

如果查询

select id,name,sex from user where name = '小白';

这个sql会先查询name索引树获取符合条件的id列表。然后再回表查询主键索引树获取sex字段数据。这就要拆线呢两次数据。

如果创建一个联合索引就可以不用多查询一次了。
ALTER TABLE user ADD INDEX index_name_sex (name,sex);: 添加name字段普通索引;

这样就拆线呢一次就能获取到所有需要的字段了。

结果:

所以在给表创建索引的时候最好创建联合索引。不要创建单个索引,一张表可以用两三个联合索引能概括全你所有的查询。不要使用select * 查询数据。每次查询最好返回自己有用的数据。不要返回无用的。

相关推荐
程序猿小D9 分钟前
[附源码+数据库+毕业论文]基于Spring+MyBatis+MySQL+Maven+jsp实现的电影小说网站管理系统,推荐!
java·数据库·mysql·spring·毕业设计·ssm框架·电影小说网站
羊小猪~~15 分钟前
数据库学习笔记(十七)--触发器的使用
数据库·人工智能·后端·sql·深度学习·mysql·考研
叁沐1 小时前
MySQL 05 深入浅出索引(下)
mysql
陈卓4102 小时前
MySQL-主从复制&分库分表
android·mysql·adb
你都会上树?2 小时前
MySQL MVCC 详解
数据库·mysql
长征coder3 小时前
AWS MySQL 读写分离配置指南
mysql·云计算·aws
ladymorgana4 小时前
【docker】修改 MySQL 密码后 Navicat 仍能用原密码连接
mysql·adb·docker
PanZonghui4 小时前
Centos项目部署之安装数据库MySQL8
linux·后端·mysql
GreatSQL社区4 小时前
用systemd管理GreatSQL服务详解
数据库·mysql·greatsql
掘根4 小时前
【MySQL进阶】错误日志,二进制日志,mysql系统库
数据库·mysql