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);
        }
    }

}

红黑树

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字段普通索引

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

结果:

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值