• 1.索引的本质


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

    二叉树

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

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

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

    @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
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75

    红黑树

    image.png

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

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

    B树

    image.png
    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+ 树

    image.png

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

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

    结果\层BB+
    1161600
    216 * 16 = 2561600 * 1600 = 2560000
    3256 * 16 = 40962560000 * 16 = 40960000

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

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

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

    索引覆盖

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

    比如:
    创建一个user表:

    creat table user(
    	id int primary key,
    	name varchar(20),
    	sex varchar(5)
    ) engine=innodb;
    ALTER TABLE user ADD INDEX index_name (name);: 添加name字段普通索引
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    如果查询
    select id,name,sex from user where name = ‘小白’;
    这个sql会先查询name索引树获取符合条件的id列表。然后再回表查询主键索引树获取sex字段数据。这就要拆线呢两次数据。
    如果创建一个联合索引就可以不用多查询一次了。
    ALTER TABLE user ADD INDEX index_name_sex (name,sex);: 添加name字段普通索引;
    这样就拆线呢一次就能获取到所有需要的字段了。

    结果:

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

  • 相关阅读:
    《Effective Java》阅读笔记
    申请ISO14001认证组织需要准备哪些资料
    我要写整个中文互联网界最牛逼的JVM系列教程 | 「JVM与Java体系架构」章节:面向人群和教程特点
    智能手机主动安全防护系统设计与实现
    Nginx快速上手
    如何用大模型RAG做医疗问答系统
    尚硅谷大数据项目《在线教育之实时数仓》笔记001
    2154. 将找到的值乘以 2
    axis和axis2的一些发布差异(WSDL2Java)
    Java21 LTS版本
  • 原文地址:https://blog.csdn.net/weixin_44806772/article/details/134505668