精华内容
下载资源
问答
  • Oracle数据库索引底层实现原理笔记

    千次阅读 2020-08-19 16:49:20
    想要理解索引原理必须清楚一种数据结构「平衡树」(非二叉),也就是b tree或者 b+ tree,重要的事情说三遍:“平衡树,平衡树,平衡树”。当然, 有的数据库也使用哈希桶作用索引的数据结构 , 然而, 主流的RDBMS都...
    • 为什么要给表加上主键?

    • 为什么加索引后会使查询变快?

    • 为什么加索引后会使写入、修改、删除变慢?

    • 什么情况下要同时在两个字段上建索引?
      想要理解索引原理必须清楚一种数据结构「平衡树」(非二叉),也就是b tree或者 b+ tree,重要的事情说三遍:“平衡树,平衡树,平衡树”。当然, 有的数据库也使用哈希桶作用索引的数据结构 , 然而, 主流的RDBMS都是把平衡树当做数据表默认的索引数据结构的。

    我们平时建表的时候都会为表加上主键, 在某些关系数据库中, 如果建表时不指定主键,数据库会拒绝建表的语句执行。 事实上, 一个加了主键的表,并不能被称之为「表」。一个没加主键的表,它的数据无序的放置在磁盘存储器上,一行一行的排列的很整齐, 跟我认知中的「表」很接近。如果给表上了主键,那么表在磁盘上的存储结构就由整齐排列的结构转变成了树状结构,也就是上面说的「平衡树」结构,换句话说,就是整个表就变成了一个索引。没错, 再说一遍, 整个表变成了一个索引,也就是所谓的「聚集索引」。 这就是为什么一个表只能有一个主键, 一个表只能有一个「聚集索引」,因为主键的作用就是把「表」的数据格式转换成「索引(平衡树)」的格式放置。

    在这里插入图片描述

    上图就是带有主键的表(聚集索引)的结构图。图画的不是很好, 将就着看。其中树的所有结点(底部除外)的数据都是由主键字段中的数据构成,也就是通常我们指定主键的id字段。最下面部分是真正表中的数据。 假如我们执行一个SQL语句:

    select * from table where id = 1256;

    首先根据索引定位到1256这个值所在的叶结点,然后再通过叶结点取到id等于1256的数据行。 这里不讲解平衡树的运行细节, 但是从上图能看出,树一共有三层, 从根节点至叶节点只需要经过三次查找就能得到结果。如下图

    在这里插入图片描述

    假如一张表有一亿条数据 ,需要查找其中某一条数据,按照常规逻辑, 一条一条的去匹配的话, 最坏的情况下需要匹配一亿次才能得到结果,用大O标记法就是O(n)最坏时间复杂度,这是无法接受的,而且这一亿条数据显然不能一次性读入内存供程序使用, 因此, 这一亿次匹配在不经缓存优化的情况下就是一亿次IO开销,以现在磁盘的IO能力和CPU的运算能力, 有可能需要几个月才能得出结果 。如果把这张表转换成平衡树结构(一棵非常茂盛和节点非常多的树),假设这棵树有10层,那么只需要10次IO开销就能查找到所需要的数据, 速度以指数级别提升,用大O标记法就是O(log n),n是记录总树,底数是树的分叉数,结果就是树的层次数。换言之,查找次数是以树的分叉数为底,记录总数的对数,用公式来表示就是

    在这里插入图片描述

    用程序来表示就是Math.Log(100000000,10),100000000是记录数,10是树的分叉数(真实环境下分叉数远不止10), 结果就是查找次数,这里的结果从亿降到了个位数。因此,利用索引会使数据库查询有惊人的性能提升。

    然而, 事物都是有两面的, 索引能让数据库查询数据的速度上升, 而使写入数据的速度下降,原因很简单的, 因为平衡树这个结构必须一直维持在一个正确的状态, 增删改数据都会改变平衡树各节点中的索引数据内容,破坏树结构, 因此,在每次数据改变时, DBMS必须去重新梳理树(索引)的结构以确保它的正确,这会带来不小的性能开销,也就是为什么索引会给查询以外的操作带来副作用的原因。

    讲完聚集索引 , 接下来聊一下非聚集索引, 也就是我们平时经常提起和使用的常规索引。

    非聚集索引和聚集索引一样, 同样是采用平衡树作为索引的数据结构。索引树结构中各节点的值来自于表中的索引字段, 假如给user表的name字段加上索引 , 那么索引就是由name字段中的值构成,在数据改变时, DBMS需要一直维护索引结构的正确性。如果给表中多个字段加上索引 , 那么就会出现多个独立的索引结构,每个索引(非聚集索引)互相之间不存在关联。 如下图

    在这里插入图片描述

    每次给字段建一个新索引, 字段中的数据就会被复制一份出来, 用于生成索引。 因此, 给表添加索引,会增加表的体积, 占用磁盘存储空间。

    非聚集索引和聚集索引的区别在于, 通过聚集索引可以查到需要查找的数据, 而通过非聚集索引可以查到记录对应的主键值 , 再使用主键的值通过聚集索引查找到需要的数据,如下图

    在这里插入图片描述

    不管以任何方式查询表, 最终都会利用主键通过聚集索引来定位到数据, 聚集索引(主键)是通往真实数据所在的唯一路径。

    然而, 有一种例外可以不使用聚集索引就能查询出所需要的数据, 这种非主流的方法 称之为「覆盖索引」查询, 也就是平时所说的复合索引或者多字段索引查询。 文章上面的内容已经指出, 当为字段建立索引以后, 字段中的内容会被同步到索引之中, 如果为一个索引指定两个字段, 那么这个两个字段的内容都会被同步至索引之中。

    先看下面这个SQL语句

    //建立索引

    create index index_birthday on user_info(birthday);

    //查询生日在1991年11月1日出生用户的用户名

    select user_name from user_info where birthday = ‘1991-11-1’

    这句SQL语句的执行过程如下

    首先,通过非聚集索引index_birthday查找birthday等于1991-11-1的所有记录的主键ID值

    然后,通过得到的主键ID值执行聚集索引查找,找到主键ID值对就的真实数据(数据行)存储的位置

    最后, 从得到的真实数据中取得user_name字段的值返回, 也就是取得最终的结果

    我们把birthday字段上的索引改成双字段的覆盖索引

    create index index_birthday_and_user_name on user_info(birthday, user_name);

    这句SQL语句的执行过程就会变为

    通过非聚集索引index_birthday_and_user_name查找birthday等于1991-11-1的叶节点的内容,然而, 叶节点中除了有user_name表主键ID的值以外, user_name字段的值也在里面, 因此不需要通过主键ID值的查找数据行的真实所在, 直接取得叶节点中user_name的值返回即可。 通过这种覆盖索引直接查找的方式, 可以省略不使用覆盖索引查找的后面两个步骤, 大大的提高了查询性能,如下图

    在这里插入图片描述

    数据库索引的大致工作原理就是像文中所述, 然而细节方面可能会略有偏差,这但并不会对概念阐述的结果产生影响 。

    展开全文
  • Reference:你心里没点b树,敢说你懂数据库索引底层原理? 要了解数据库索引的底层原理,我们就得先了解一种叫树的数据结构,而树中很经典的一种数据结构就是二叉树!所以下面我们就从二叉树到平衡二叉树,再到B-树...

    Reference: 你心里没点b树,敢说你懂数据库索引底层原理?

    要了解数据库索引的底层原理,我们就得先了解一种叫树的数据结构,而树中很经典的一种数据结构就是二叉树!所以下面我们就从二叉树到平衡二叉树,再到B-树,最后到B+树来一步一步了解数据库索引底层的原理!

    二叉查找树(Binary Search Trees)

     

    二叉树是每个结点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。二叉树常被用于实现二叉查找树和二叉堆。二叉树有如下特性:

    1、每个结点都包含一个元素以及n个子树,这里0≤n≤2。
    2、左子树和右子树是有顺序的,次序不能任意颠倒。左子树的值要小于父结点,右子树的值要大于父结点。

      光看概念有点枯燥,假设我们现在有这样一组数[35 27 48 12 29 38 55],顺序的插入到一个数的结构中,步骤如下




      好了,这就是一棵二叉树啦!我们能看到,经通过一系列的插入操作之后,原本无序的一组数已经变成一个有序的结构了,并且这个树满足了上面提到的两个二叉树的特性!

      但是如果同样是上面那一组数,我们自己升序排列后再插入,也就是说按照[12 27 29 35 38 48 55]的顺序插入,会怎么样呢?

      由于是升序插入,新插入的数据总是比已存在的结点数据都要大,所以每次都会往结点的右边插入,最终导致这棵树严重偏科!!!上图就是最坏的情况,也就是一棵树退化为一个线性链表了,这样查找效率自然就低了,完全没有发挥树的优势了呢!
    为了较大发挥二叉树的查找效率,让二叉树不再偏科,保持各科平衡,所以有了平衡二叉树!

    平衡二叉树 (AVL Trees)

    平衡二叉树是一种特殊的二叉树,所以他也满足前面说到的二叉树的两个特性,同时还有一个特性:

    它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

      大家也看到了前面[35 27 48 12 29 38 55]插入完成后的图,其实就已经是一颗平衡二叉树啦。

      那如果按照[12 27 29 35 38 48 55]的顺序插入一颗平衡二叉树,会怎么样呢?我们看看插入以及平衡的过程:







      这棵树始终满足平衡二叉树的几个特性而保持平衡!这样我们的树也不会退化为线性链表了!我们需要查找一个数的时候就能沿着树根一直往下找,这样的查找效率和二分法查找是一样的呢!

      一颗平衡二叉树能容纳多少的结点呢?这跟树的高度是有关系的,假设树的高度为h,那每一层最多容纳的结点数量为2^(n-1),整棵树最多容纳节点数为2^0+2^1+2^2+...+2^(h-1)。这样计算,100w数据树的高度大概在20左右,那也就是说从有着100w条数据的平衡二叉树中找一个数据,最坏的情况下需要20次查找。如果是内存操作,效率也是很高的!但是我们数据库中的数据基本都是放在磁盘中的,每读取一个二叉树的结点就是一次磁盘IO,这样我们找一条数据如果要经过20次磁盘的IO?那性能就成了一个很大的问题了!那我们是不是可以把这棵树压缩一下,让每一层能够容纳更多的节点呢?虽然我矮,但是我胖啊...

    B-Tree

    这颗矮胖的树就是B-Tree,注意中间是杠精的杠而不是减,所以也不要读成B减Tree了~

      那B-Tree有哪些特性呢?一棵m阶的B-Tree有如下特性:

    1、每个结点最多m个子结点。
    2、除了根结点和叶子结点外,每个结点最少有m/2(向上取整)个子结点。
    3、如果根结点不是叶子结点,那根结点至少包含两个子结点。
    4、所有的叶子结点都位于同一层。
    5、每个结点都包含k个元素(关键字),这里m/2≤k<m,这里m/2向下取整。
    6、每个节点中的元素(关键字)从小到大排列。
    7、每个元素(关键字)字左结点的值,都小于或等于该元素(关键字)。右结点的值都大于或等于该元素(关键字)。

      是不是感觉跟丈母娘张口问你要彩礼一样,列一堆的条件,而且每一条都让你很懵逼!下面我们以一个[0,1,2,3,4,5,6,7]的数组插入一颗3阶的B-Tree为例,将所有的条件都串起来,你就明白了!






      那么,你是否对B-Tree的几点特性都清晰了呢?在二叉树中,每个结点只有一个元素。但是在B-Tree中,每个结点都可能包含多个元素,并且非叶子结点在元素的左右都有指向子结点的指针。

      如果需要查找一个元素,那流程是怎么样的呢?我们看下图,如果我们要在下面的B-Tree中找到关键字24,那流程如下



      从这个流程我们能看出,B-Tree的查询效率好像也并不比平衡二叉树高。但是查询所经过的结点数量要少很多,也就意味着要少很多次的磁盘IO,这对
    性能的提升是很大的。

      前面对B-Tree操作的图我们能看出来,元素就是类似1、2、3这样的数值,但是数据库的数据都是一条条的数据,如果某个数据库以B-Tree的数据结构存储数据,那数据怎么存放的呢?我们看下一张图

      普通的B-Tree的结点中,元素就是一个个的数字。但是上图中,我们把元素部分拆分成了key-data的形式,key就是数据的主键,data就是具体的数据。这样我们在找一条数的时候,就沿着根结点往下找就ok了,效率是比较高的。

    B+Tree

     

    B+Tree是在B-Tree基础上的一种优化,使其更适合实现外存储索引结构。B+Tree与B-Tree的结构很像,但是也有几个自己的特性:

    1、所有的非叶子节点只存储关键字信息。
    2、所有卫星数据(具体数据)都存在叶子结点中。
    3、所有的叶子结点中包含了全部元素的信息。
    4、所有叶子节点之间都有一个链指针。

      如果上面B-Tree的图变成B+Tree,那应该如下:

      大家仔细对比于B-Tree的图能发现什么不同?
      1、非叶子结点上已经只有key信息了,满足上面第1点特性!
      2、所有叶子结点下面都有一个data区域,满足上面第2点特性!
      3、非叶子结点的数据在叶子结点上都能找到,如根结点的元素4、8在最底层的叶子结点上也能找到,满足上面第3点特性!
      4、注意图中叶子结点之间的箭头,满足满足上面第4点特性!

    B-Tree or B+Tree?

      在讲这两种数据结构在数据库中的选择之前,我们还需要了解的一个知识点是操作系统从磁盘读取数据到内存是以磁盘块(block)为基本单位的,位于同一个磁盘块中的数据会被一次性读取出来,而不是需要什么取什么。即使只需要一个字节,磁盘也会从这个位置开始,顺序向后读取一定长度的数据放入内存。这样做的理论依据是计算机科学中著名的局部性原理:当一个数据被用到时,其附近的数据也通常会马上被使用。
      预读的长度一般为页(page)的整倍数。页是计算机管理存储器的逻辑块,硬件及操作系统往往将主存和磁盘存储区分割为连续的大小相等的块,每个存储块称为一页(在许多操作系统中,页得大小通常为4k)。

      B-Tree和B+Tree该如何选择呢?都有哪些优劣呢?
      1、B-Tree因为非叶子结点也保存具体数据,所以在查找某个关键字的时候找到即可返回。而B+Tree所有的数据都在叶子结点,每次查找都得到叶子结点。所以在同样高度的B-Tree和B+Tree中,B-Tree查找某个关键字的效率更高。
      2、由于B+Tree所有的数据都在叶子结点,并且结点之间有指针连接,在找大于某个关键字或者小于某个关键字的数据的时候,B+Tree只需要找到该关键字然后沿着链表遍历就可以了,而B-Tree还需要遍历该关键字结点的根结点去搜索。
      3、由于B-Tree的每个结点(这里的结点可以理解为一个数据页)都存储主键+实际数据,而B+Tree非叶子结点只存储关键字信息,而每个页的大小有限是有限的,所以同一页能存储的B-Tree的数据会比B+Tree存储的更少。这样同样总量的数据,B-Tree的深度会更大,增大查询时的磁盘I/O次数,进而影响查询效率。
      鉴于以上的比较,所以在常用的关系型数据库中,都是选择B+Tree的数据结构来存储数据!下面我们以mysql的innodb存储引擎为例讲解,其他类似sqlserver、oracle的原理类似!

    innodb引擎数据存储

      在InnoDB存储引擎中,也有页的概念,默认每个页的大小为16K,也就是每次读取数据时都是读取4*4k的大小!假设我们现在有一个用户表,我们往里面写数据

      这里需要注意的一点是,在某个页内插入新行时,为了不减少数据的移动,通常是插入到当前行的后面或者是已删除行留下来的空间,所以在某一个页内的数据并不是完全有序的(后面页结构部分有细讲),但是为了为了数据访问顺序性,在每个记录中都有一个指向下一条记录的指针,以此构成了一条单向有序链表,不过在这里为了方便演示我是按顺序排列的!

      由于数据还比较少,一个页就能容下,所以只有一个根结点,主键和数据也都是保存在根结点(左边的数字代表主键,右边名字、性别代表具体的数据)。假设我们写入10条数据之后,Page1满了,再写入新的数据会怎么存放呢?我们继续看下图

      有个叫“秦寿生”的朋友来了,但是Page1已经放不下数据了,这时候就需要进行页分裂,产生一个新的Page。在innodb中的流程是怎么样的呢?

    1、产生新的Page2,然后将Page1的内容复制到Page2。
    2、产生新的Page3,“秦寿生”的数据放入Page3。
    3、原来的Page1依然作为根结点,但是变成了一个不存放数据只存放索引的页,并且有两个子结点Page2、Page3。

      这里有两个问题需要注意的是
      1、为什么要复制Page1为Page2而不是创建一个新的页作为根结点,这样就少了一步复制的开销了?
      如果是重新创建根结点,那根结点存储的物理地址可能经常会变,不利于查找。并且在innodb中根结点是会预读到内存中的,所以结点的物理地址固定会比较好!

      2、原来Page1有10条数据,在插入第11条数据的时候进行裂变,根据前面对B-Tree、B+Tree特性的了解,那这至少是一颗11阶的树,裂变之后每个结点的元素至少为11/2=5个,那是不是应该页裂变之后主键1-5的数据还是在原来的页,主键6-11的数据会放到新的页,根结点存放主键6?
      如果是这样的话新的页空间利用率只有50%,并且会导致更为频繁的页分裂。所以innodb对这一点做了优化,新的数据放入新创建的页,不移动原有页面的任何记录。

      随着数据的不断写入,这棵树也逐渐枝繁叶茂,如下图

      每次新增数据,都是将一个页写满,然后新创建一个页继续写,这里其实是有个隐含条件的,那就是主键自增!主键自增写入时新插入的数据不会影响到原有页,插入效率高!且页的利用率高!但是如果主键是无序的或者随机的,那每次的插入可能会导致原有页频繁的分裂,影响插入效率!降低页的利用率!这也是为什么在innodb中建议设置主键自增的原因!

      这棵树的非叶子结点上存的都是主键,那如果一个表没有主键会怎么样?在innodb中,如果一个表没有主键,那默认会找建了唯一索引的列,如果也没有,则会生成一个隐形的字段作为主键!

      有数据插入那就有删除,如果这个用户表频繁的插入和删除,那会导致数据页产生碎片,页的空间利用率低,还会导致树变的“虚高”,降低查询效率!这可以通过索引重建来消除碎片提高查询效率!

    innodb引擎数据查找

      数据插入了怎么查找呢?

    1、找到数据所在的页。这个查找过程就跟前面说到的B+Tree的搜索过程是一样的,从根结点开始查找一直到叶子结点。
    2、在页内找具体的数据。读取第1步找到的叶子结点数据到内存中,然后通过分块查找的方法找到具体的数据。

      这跟我们在新华字典中找某个汉字是一样的,先通过字典的索引定位到该汉字拼音所在的页,然后到指定的页找到具体的汉字。innodb中定位到页后用了哪种策略快速查找某个主键呢?这我们就需要从页结构开始了解。

      左边蓝色区域称为Page Directory,这块区域由多个slot组成,是一个稀疏索引结构,即一个槽中可能属于多个记录,最少属于4条记录,最多属于8条记录。槽内的数据是有序存放的,所以当我们寻找一条数据的时候可以先在槽中通过二分法查找到一个大致的位置。

      右边区域为数据区域,每一个数据页中都包含多条行数据。注意看图中最上面和最下面的两条特殊的行记录Infimum和Supremum,这是两个虚拟的行记录。在没有其他用户数据的时候Infimum的下一条记录的指针指向Supremum,当有用户数据的时候,Infimum的下一条记录的指针指向当前页中最小的用户记录,当前页中最大的用户记录的下一条记录的指针指向Supremum,至此整个页内的所有行记录形成一个单向链表。

      行记录被Page Directory逻辑的分成了多个块,块与块之间是有序的,也就是说“4”这个槽指向的数据块内最大的行记录的主键都要比“8”这个槽指向的数据块内最小的行记录的主键要小。但是块内部的行记录不一定有序。

      每个行记录的都有一个n_owned的区域(图中粉红色区域),n_owned标识这个这个块有多少条数据,伪记录Infimum的n_owned值总是1,记录Supremum的n_owned的取值范围为[1,8],其他用户记录n_owned的取值范围[4,8],并且只有每个块中最大的那条记录的n_owned才会有值,其他的用户记录的n_owned为0。

      所以当我们要找主键为6的记录时,先通过二分法稀疏索引中找到对应的槽,也就是Page Directory中“8”这个槽,“8”这个槽指向的是该数据块中最大的记录,而数据是单向链表结构所以无法逆向查找,所以需要找到上一个槽即“4”这个槽,然后通过“4”这个槽中最大的用户记录的指针沿着链表顺序查找到目标记录。

    聚集索引&非聚集索引

      前面关于数据存储的都是演示的聚集索引的实现,如果上面的用户表需要以“用户名字”建立一个非聚集索引,是怎么实现的呢?我们看下图:

      非聚集索引的存储结构与前面是一样的,不同的是在叶子结点的数据部分存的不再是具体的数据,而数据的聚集索引的key。所以通过非聚集索引查找的过程是先找到该索引key对应的聚集索引的key,然后再拿聚集索引的key到主键索引树上查找对应的数据,这个过程称为回表

      图中的这些名字均来源于网络,希望没有误伤正在看这篇文章的你~^_^

    innodb与MyISAM两种存储引擎对比

      上面包括存储和搜索都是拿的innodb引擎为例,那MyISAM与innodb在存储上有啥不同呢?憋缩话,看图:

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

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

      也就是说innodb引擎数据在物理上是按主键顺序存放,而MyISAM引擎数据在物理上按插入的顺序存放。并且MyISAM的叶子结点不存放数据,所以非聚集索引的存储结构与聚集索引类似,在使用非聚集索引查找数据的时候通过非聚集索引树就能直接找到数据的地址了,不需要回表,这比innodb的搜索效率会更高呢!

    索引优化建议?

      大家经常会在很多的文章或书中能看到一些索引的使用建议,比如说

    1、like的模糊查询以%开头,会导致索引失效。
    2、一个表建的索引尽量不要超过5个。
    3、尽量使用覆盖索引。
    4、尽量不要在重复数据多的列上建索引。
    5、。。。。。。。。。。。
    6、。。。。。。。。。。。

      很多这里就不一一列举了!那看完这篇文章,我们能否带着疑问去分析一下为什么要有这些建议?为什么like的模糊查询以%开头,会导致索引失效?为什么一个表建的索引尽量不要超过5个?为什么?为什么??为什么???相信看到这里的你再加上自己的一些思考应该有答案了吧?

     

     

    展开全文
  • Oracle索引原理

    千次阅读 2017-10-23 17:17:18
    索引原理 oracle中的索引与mysql中的索引不一样,oracle索引是存储了索引列的值以及rowid值。而mysql索引分为聚集索引,非聚集索引。其中聚集索引只能有一个。 oracle索引的主要分为根,茎,叶子三部分。索引列...

    索引原理

    1. oracel中索引类型很多,默认采用B树索引。
    2. oracle中的索引与mysql中的索引不一样,oracle中索引是存储了索引列的值以及rowid值。而mysql索引分为聚集索引,非聚集索引。其中聚集索引只能有一个。
    3. oracle中索引的主要分为根,茎,叶子三部分。索引列值都是存放在叶子节点上,茎只是存放了叶子节点的相关信息。
    4. oracle中的索引反应的是逻辑结构,不是物理结构。索引创建的时候,是先创建叶子节点,然后再创建茎,最后创建根。从索引的创建过程分析可以看出来。
    5. oracle中数据单位是以块为单位的,数据存储满一个数据块block,再去存储下一个数据块block。

    索引特点

    1. 索引高度一般比较低
    2. 索引是按照有序排列的。
    3. 索引存储列值及rowid值

    如何建索引

    1. oracle会在主键上创建索引
    2. oracle会在非空唯一索引列上创建索引。
    3. 经常出现的谓词,即出现在执行频率很高的SQL查询的where条件中的列上。
    4. 索引最好有单独的表空间,有利于备份和维护

    索引缺点

    1. 索引需要占据存储空间,索引能提供查询速度,但是维护和更新却浪费空间。因为索引是有序排列的。

    影响性能缘由

    1. oracle中sql语句,在查询时影响性能主要有逻辑读,排序,花费时间time代价cost(cpu)全表扫描等多个因素。

    索引应用

    1. order by
      1.1 order by 列名。会对order by 后面的列进行排序,
    2. distinct
      2.1 distinct 会进行排序

    索引压缩

    1. 在索引列中(一列或者多列),如果有多行数值相同,为了提供查询数据速度,可以将索引进行压缩存储。索引最终也是要存储在数据块上,压缩索引是为了减少扫描数据块的个数。
    2. 可以采用compress N子句方式创建压缩索引。
    3. create index index_name on tableName(col1,col2) compress N。
      3.1 如果N为1,则会对第一列进行压缩存储,N为2,则会对第一列和第二列压缩存储。

    组合索引设计

    1. 适当场合尽量避免回表读
    2. 组合索引中的列数越少越高效
    3. 组合索引中有2列时,情况又不一样:
      3.1 组合索引中,等值查询时,无论哪列在前在后都无所谓。
      3.2 组合索引的2列中,如果一列是范围查询,一列是等值查询,则一定要把等值查询放在前面,范围查询列放在后面才能使索引高效。这里是创建索引的时候,等值查询列在组合索引的最前面,范围列在最后面,不是sql语句中的书写顺序。
    4. 如果单列的查询与组合索引的前置列查询一样,则单列可以不用创建索引,直接利用组合索引来检索数据。最好将该列放在组合索引的第一列
    5. 经常一起出现在where字句中的列可以创建索引

    函数索引

    1. 在SQL查询中,如果where条件中的列上创建了索引,但是在该索引列上使用了函数,则oracle函数会使当前列上的索引失效。
    2. 对于上述情况,需要创建函数索引。
    3. 创建函数索引需要在创建语句中指定使用的函数和列。create index index_name on table_name(函数(列名))
    4. 如果创建了函数索引,则不能直接修改。需要先删除索引,再修改列,然后重建。

    不可见索引

    1. 有时候想增加一个索引而又不影响线上应用的性能,即通知SQL优化器默认不使用该索引。需要在创建索引的时候,设置为不可见。
    2. create index index_Name on table_name(col1,col2) invisible。
    3. 创建完索引后,需要确保optimizer_use_invisible_indexes的值为true。可以使用alter system set optimizer_use_invisible_indexes= true
    4. 使用hit提示,可以显示通知优化器使用该索引。

    查看表中索引方式

    1. 可以在表user_indexes中查看索引方式 。
    展开全文
  • 数据库索引底层原理

    2019-07-23 15:37:19
    二叉树到平衡二叉树,再到 B- 树,最后到 B+ 树来一步一步了解数据库索引底层原理! 二叉树(Binary Search Trees) 二叉树是每个结点最多有两个子树的树结构。通常子树被称作“左子树”(Left Subtree)和“右...

    转载:

    https://mp.weixin.qq.com/s/QzJUWqa51uAQJcXPAqoC9g

    二叉树到平衡二叉树,再到 B- 树,最后到 B+ 树来一步一步了解数据库索引底层的原理!

    二叉树(Binary Search Trees)

    二叉树是每个结点最多有两个子树的树结构。通常子树被称作“左子树”(Left Subtree)和“右子树”(Right Subtree)。二叉树常被用于实现二叉查找树和二叉堆。

    二叉树有如下特性:

    • 每个结点都包含一个元素以及 n 个子树,这里 0≤n≤2。 

    • 左子树和右子树是有顺序的,次序不能任意颠倒。左子树的值要小于父结点,右子树的值要大于父结点。

    光看概念有点枯燥,假设我们现在有这样一组数[35 27 48 12 29 38 55],顺序的插入到一个数的结构中,步骤如下 :

    好了,这就是一棵二叉树啦!我们能看到,经过一系列的插入操作之后,原本无序的一组数已经变成一个有序的结构了,并且这个树满足了上面提到的两个二叉树的特性!

     

    但是如果同样是上面那一组数,我们自己升序排列后再插入,也就是说按照[12 27 29 35 38 48 55]的顺序插入,会怎么样呢?

    由于是升序插入,新插入的数据总是比已存在的结点数据都要大,所以每次都会往结点的右边插入,最终导致这棵树严重偏科!

    上图就是最坏的情况,也就是一棵树退化为一个线性链表了,这样查找效率自然就低了,完全没有发挥树的优势了呢! 

    为了较大发挥二叉树的查找效率,让二叉树不再偏科,保持各科平衡,所以有了平衡二叉树!

    平衡二叉树 (AVL Trees)

    平衡二叉树是一种特殊的二叉树,所以他也满足前面说到的二叉树的两个特性,同时还有一个特性:它的左右两个子树的高度差的绝对值不超过 1,并且左右两个子树都是一棵平衡二叉树。

    大家也看到了前面[35 27 48 12 29 38 55]插入完成后的图,其实就已经是一棵平衡二叉树啦。

    那如果按照[12 27 29 35 38 48 55]的顺序插入一棵平衡二叉树,会怎么样呢?

    我们看看插入以及平衡的过程:

    这棵树始终满足平衡二叉树的几个特性而保持平衡!这样我们的树也不会退化为线性链表了!

    我们需要查找一个数的时候就能沿着树根一直往下找,这样的查找效率和二分法查找是一样的呢!

    一棵平衡二叉树能容纳多少的结点呢?这跟树的高度是有关系的,假设树的高度为 h,那每一层最多容纳的结点数量为 2^(n-1),整棵树最多容纳节点数为 2^0+2^1+2^2+...+2^(h-1)。

    这样计算,100w 数据树的高度大概在 20 左右,也就是说从有着 100w 条数据的平衡二叉树中找一个数据,最坏的情况下需要 20 次查找。

    如果是内存操作,效率也是很高的!但是我们数据库中的数据基本都是放在磁盘中的,每读取一个二叉树的结点就是一次磁盘 IO,这样我们找一条数据如果要经过 20 次磁盘的 IO?

    那性能就成了一个很大的问题了!那我们是不是可以把这棵树压缩一下,让每一层能够容纳更多的节点呢?虽然我矮,但是我胖啊...

     

    B-Tree

    这颗矮胖的树就是 B-Tree,注意中间是杠精的杠而不是减,所以也不要读成 B 减 Tree 了~

    那 B-Tree 有哪些特性呢?一棵 m 阶的 B-Tree 有如下特性:

    • 每个结点最多 m 个子结点。 

    • 除了根结点和叶子结点外,每个结点最少有 m/2(向上取整)个子结点。 

    • 如果根结点不是叶子结点,那根结点至少包含两个子结点。 

    • 所有的叶子结点都位于同一层。 

    • 每个结点都包含 k 个元素(关键字),这里 m/2≤k。

    • 每个节点中的元素(关键字)从小到大排列。 

    • 每个元素(关键字)字左结点的值,都小于或等于该元素(关键字)。右结点的值都大于或等于该元素(关键字)。

    是不是感觉跟丈母娘张口问你要彩礼一样,列一堆的条件,而且每一条都让你很懵逼!

    下面我们以一个[0,1,2,3,4,5,6,7]的数组插入一棵 3 阶的 B-Tree 为例,将所有的条件都串起来,你就明白了!

    那么,你是否对 B-Tree 的几点特性都清晰了呢?在二叉树中,每个结点只有一个元素。

    但是在 B-Tree 中,每个结点都可能包含多个元素,并且非叶子结点在元素的左右都有指向子结点的指针。

    如果需要查找一个元素,那流程是怎么样的呢?我们看下图,如果我们要在下面的 B-Tree 中找到关键字 24,那流程如下:

    从这个流程我们能看出,B-Tree 的查询效率好像也并不比平衡二叉树高。但是查询所经过的结点数量要少很多,也就意味着要少很多次的磁盘 IO,这对性能的提升是很大的。

    从前面对 B-Tree 操作的图,我们能看出来,元素就是类似 1、2、3 这样的数值。

    但是数据库的数据都是一条条的数据,如果某个数据库以 B-Tree 的数据结构存储数据,那数据怎么存放的呢?

    我们看下一张图:

    普通的 B-Tree 的结点中,元素就是一个个的数字。但是上图中,我们把元素部分拆分成了 key-data 的形式,Key 就是数据的主键,Data 就是具体的数据。

    这样我们在找一条数的时候,就沿着根结点往下找就 OK 了,效率是比较高的。

    B+Tree

    B+Tree 是在 B-Tree 基础上的一种优化,使其更适合实现外存储索引结构。

    B+Tree 与 B-Tree 的结构很像,但是也有几个自己的特性:

    • 所有的非叶子节点只存储关键字信息。 

    • 所有卫星数据(具体数据)都存在叶子结点中。 

    • 所有的叶子结点中包含了全部元素的信息。 

    • 所有叶子节点之间都有一个链指针。

    如果上面 B-Tree 的图变成 B+Tree,那应该如下: 

    大家仔细对比于 B-Tree 的图能发现什么不同? 

    • 非叶子结点上已经只有 Key 信息了,满足上面第 1 点特性! 

    • 所有叶子结点下面都有一个 Data 区域,满足上面第 2 点特性! 

    • 非叶子结点的数据在叶子结点上都能找到,如根结点的元素 4、8 在最底层的叶子结点上也能找到,满足上面第 3 点特性! 

    • 注意图中叶子结点之间的箭头,满足上面第 4 点特性!

     

    B-Tree or B+Tree?

    在讲这两种数据结构在数据库中的选择之前,我们还需要了解的一个知识点是操作系统从磁盘读取数据到内存是以磁盘块(Block)为基本单位的,位于同一个磁盘块中的数据会被一次性读取出来,而不是需要什么取什么。

    即使只需要一个字节,磁盘也会从这个位置开始,顺序向后读取一定长度的数据放入内存。

    这样做的理论依据是计算机科学中著名的局部性原理:当一个数据被用到时,其附近的数据也通常会马上被使用。 

    预读的长度一般为页(Page)的整倍数。页是计算机管理存储器的逻辑块,硬件及操作系统往往将主存和磁盘存储区分割为连续的大小相等的块,每个存储块称为一页(在许多操作系统中,页的大小通常为 4K)。

    B-Tree 和 B+Tree 该如何选择呢?都有哪些优劣呢?

    ①B-Tree 因为非叶子结点也保存具体数据,所以在查找某个关键字的时候找到即可返回。

    而 B+Tree 所有的数据都在叶子结点,每次查找都得到叶子结点。所以在同样高度的 B-Tree 和 B+Tree 中,B-Tree 查找某个关键字的效率更高。 

    ②由于 B+Tree 所有的数据都在叶子结点,并且结点之间有指针连接,在找大于某个关键字或者小于某个关键字的数据的时候,B+Tree 只需要找到该关键字然后沿着链表遍历就可以了,而 B-Tree 还需要遍历该关键字结点的根结点去搜索。 

    ③由于 B-Tree 的每个结点(这里的结点可以理解为一个数据页)都存储主键+实际数据,而 B+Tree 非叶子结点只存储关键字信息,而每个页的大小是有限的,所以同一页能存储的 B-Tree 的数据会比 B+Tree 存储的更少。

    这样同样总量的数据,B-Tree 的深度会更大,增大查询时的磁盘 I/O 次数,进而影响查询效率。 

    鉴于以上的比较,所以在常用的关系型数据库中,都是选择 B+Tree 的数据结构来存储数据!

    下面我们以 MySQL 的 InnoDB 存储引擎为例讲解,其他类似 SQL Server、Oracle 的原理!

     

    InnoDB 引擎数据存储

    在 InnoDB 存储引擎中,也有页的概念,默认每个页的大小为 16K,也就是每次读取数据时都是读取 4*4K 的大小!

    假设我们现在有一个用户表,我们往里面写数据:

    这里需要注意的一点是,在某个页内插入新行时,为了减少数据的移动,通常是插入到当前行的后面或者是已删除行留下来的空间,所以在某一个页内的数据并不是完全有序的(后面页结构部分有细讲)。

    但是为了数据访问顺序性,在每个记录中都有一个指向下一条记录的指针,以此构成了一条单向有序链表,不过在这里为了方便演示我是按顺序排列的!

    由于数据还比较少,一个页就能容下,所以只有一个根结点,主键和数据也都是保存在根结点(左边的数字代表主键,右边名字、性别代表具体的数据)。

    假设我们写入 10 条数据之后,Page1 满了,再写入新的数据会怎么存放呢?

    我们继续看下图:

    有个叫“秦寿生”的朋友来了,但是 Page1 已经放不下数据了,这时候就需要进行页分裂,产生一个新的 Page。

    在 InnoDB 中的流程是怎么样的呢?

    • 产生新的 Page2,然后将 Page1 的内容复制到 Page2。 

    • 产生新的 Page3,“秦寿生”的数据放入 Page3。 

    • 原来的 Page1 依然作为根结点,但是变成了一个不存放数据只存放索引的页,并且有两个子结点 Page2、Page3。

     

    这里有两个问题需要注意的是:

    ①为什么要复制 Page1 为 Page2 而不是创建一个新的页作为根结点,这样就少了一步复制的开销了?

    如果是重新创建根结点,那根结点存储的物理地址可能经常会变,不利于查找。

    并且在 InnoDB 中根结点是会预读到内存中的,所以结点的物理地址固定会比较好!

    ②原来 Page1 有 10 条数据,在插入第 11 条数据的时候进行裂变,根据前面对 B-Tree、B+Tree 特性的了解,那这至少是一棵 11 阶的树,裂变之后每个结点的元素至少为 11/2=5 个。

    那是不是应该页裂变之后主键 1-5 的数据还是在原来的页,主键 6-11 的数据会放到新的页,根结点存放主键 6? 

    如果是这样的话,新的页空间利用率只有 50%,并且会导致更为频繁的页分裂。

    所以 InnoDB 对这一点做了优化,新的数据放入新创建的页,不移动原有页面的任何记录。

    随着数据的不断写入,这棵树也逐渐枝繁叶茂,如下图:

    每次新增数据,都是将一个页写满,然后新创建一个页继续写,这里其实是有个隐含条件的,那就是主键自增!

    主键自增写入时新插入的数据不会影响到原有页,插入效率高!且页的利用率高!

    但是如果主键是无序的或者随机的,那每次的插入可能会导致原有页频繁的分裂,影响插入效率!降低页的利用率!这也是为什么在 InnoDB 中建议设置主键自增的原因!

    这棵树的非叶子结点上存的都是主键,那如果一个表没有主键会怎么样?在 InnoDB 中,如果一个表没有主键,那默认会找建了唯一索引的列,如果也没有,则会生成一个隐形的字段作为主键!

    有数据插入那就有删除,如果这个用户表频繁的插入和删除,那会导致数据页产生碎片,页的空间利用率低,还会导致树变的“虚高”,降低查询效率!这可以通过索引重建来消除碎片提高查询效率!

     

    InnoDB 引擎数据查找

    数据插入了怎么查找呢?

    • 找到数据所在的页。这个查找过程就跟前面说到的 B+Tree 的搜索过程是一样的,从根结点开始查找一直到叶子结点。 

    • 在页内找具体的数据。读取第 1 步找到的叶子结点数据到内存中,然后通过分块查找的方法找到具体的数据。

    这跟我们在新华字典中找某个汉字是一样的,先通过字典的索引定位到该汉字拼音所在的页,然后到指定的页找到具体的汉字。

    InnoDB 中定位到页后用了哪种策略快速查找某个主键呢?这我们就需要从页结构开始了解。

    左边蓝色区域称为 Page Directory,这块区域由多个 Slot 组成,是一个稀疏索引结构,即一个槽中可能属于多个记录,最少属于 4 条记录,最多属于 8 条记录。

    槽内的数据是有序存放的,所以当我们寻找一条数据的时候可以先在槽中通过二分法查找到一个大致的位置。

    右边区域为数据区域,每一个数据页中都包含多条行数据。注意看图中最上面和最下面的两条特殊的行记录 Infimum 和 Supremum,这是两个虚拟的行记录。

    在没有其他用户数据的时候 Infimum 的下一条记录的指针指向 Supremum。

    当有用户数据的时候,Infimum 的下一条记录的指针指向当前页中最小的用户记录,当前页中最大的用户记录的下一条记录的指针指向 Supremum,至此整个页内的所有行记录形成一个单向链表。

    行记录被 Page Directory 逻辑的分成了多个块,块与块之间是有序的,也就是说“4”这个槽指向的数据块内最大的行记录的主键都要比“8”这个槽指向的数据块内最小的行记录的主键要小。但是块内部的行记录不一定有序。

    每个行记录的都有一个 n_owned 的区域(图中粉红色区域),n_owned 标识这个块有多少条数据。

    伪记录 Infimum 的 n_owned 值总是 1,记录 Supremum 的 n_owned 的取值范围为[1,8],其他用户记录 n_owned 的取值范围[4,8]。

    并且只有每个块中最大的那条记录的 n_owned 才会有值,其他的用户记录的 n_owned 为 0。

    所以当我们要找主键为 6 的记录时,先通过二分法在稀疏索引中找到对应的槽,也就是 Page Directory 中“8”这个槽。

    “8”这个槽指向的是该数据块中最大的记录,而数据是单向链表结构,所以无法逆向查找。

    所以需要找到上一个槽即“4”这个槽,然后通过“4”这个槽中最大的用户记录的指针沿着链表顺序查找到目标记录。

     

    聚集索引&非聚集索引

    前面关于数据存储的都是演示的聚集索引的实现,如果上面的用户表需要以“用户名字”建立一个非聚集索引,是怎么实现的呢?

    我们看下图:

    非聚集索引的存储结构与前面是一样的,不同的是在叶子结点的数据部分存的不再是具体的数据,而是数据的聚集索引的 Key。

    所以通过非聚集索引查找的过程是先找到该索引 Key 对应的聚集索引的 Key,然后再拿聚集索引的 Key 到主键索引树上查找对应的数据,这个过程称为回表!

    PS:图中的这些名字均来源于网络,希望没有误伤正在看这篇文章的你~^_^

     

    InnoDB 与 MyISAM 引擎对比

    上面包括存储和搜索都是拿的 InnoDB 引擎为例,那 MyISAM 与 InnoDB 在存储上有啥不同呢?憋缩话,看图:

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

    • 主键索引树的叶子结点的数据区域没有存放实际的数据,存放的是数据记录的地址。 

    • 数据的存储不是按主键顺序存放的,是按写入的顺序存放。

    也就是说 InnoDB 引擎数据在物理上是按主键顺序存放,而 MyISAM 引擎数据在物理上按插入的顺序存放。

    并且 MyISAM 的叶子结点不存放数据,所以非聚集索引的存储结构与聚集索引类似,在使用非聚集索引查找数据的时候通过非聚集索引树就能直接找到数据的地址了,不需要回表,这比 InnoDB 的搜索效率会更高呢!

     

    索引优化建议

    大家经常会在很多的文章或书中能看到一些索引的使用建议,比如说:

    • like 的模糊查询以 % 开头,会导致索引失效。 

    • 一个表建的索引尽量不要超过 5 个。 

    • 尽量使用覆盖索引。 

    • 尽量不要在重复数据多的列上建索引。 

    • ......

     

    很多这里就不一一列举了!那看完这篇文章,我们能否带着疑问去分析一下为什么要有这些建议?

    为什么 like 的模糊查询以 % 开头,会导致索引失效?为什么一个表建的索引尽量不要超过 5 个?

    为什么?为什么??为什么???相信看到这里的你再加上自己的一些思考应该有答案了吧?

     

     

    展开全文
  • oracle 基本索引原理

    2012-10-14 20:23:40
    oracle 基本索引原理oracle 学习真必不可少的资料。
  • 参考文章:mysql的索引底层原理 什么是索引 概念:索引是提高mysql查询效率的数据结构。总的一句话概括就是索引是一种数据结构。 数据库查询是数据库的最主要功能之一。设计者们都希望查询数据的速度能尽可能的...
  • 一文读懂mysql索引底层原理

    千次阅读 2019-03-19 10:59:00
    数据库的底层索引是用B树和B+树实现的,但是为什么使用的是它们,为什么不用红黑树? 红黑树等数据结构也可以用来实现索引,但是文件系统以及数据库系统普遍采用B-Tree/B+Tree作为索引结构.这是因为:索引本身也很大,...
  • Oracle支持的全部索引MySQL支持的全部索引
  • MySQL官方对于索引的定义为:索引是帮助MySQL高效获取数据的数据结构。即:索引是数据结构。 我们知道,数据库查询是数据库最主要的功能之一,我们都希望查询数据的速度尽可能的快,因此数据库系统的设计者会从...
  • oracle索引有多种类型。我分类介绍下几种常用的索引 B 树索引(B-Tree索引) B树索引是我们在oracle数据库中最常用的索引,在详细介绍访问方法之前,我们看一下B-TREE索引的结构(图片来源网络) oracle的B...
  • Oracle索引游标学习

    2020-08-02 23:04:24
    oracle索引要有了解,了解索引运用原理以及复杂SQL中索引的作用,为后面优化SQL以及编写复杂逻辑SQL并保证查询效率打下基础 学习内容: oracle基本索引学习,SQL窗口执行计划(F5)了解 学习要求: 掌握oracle...
  • ORACLE 索引概述

    2014-04-15 13:38:35
    就像本文档的索引可以帮助读者快速定位所需信息一样,Oracle索引提供了更为迅速地访问表数据的方式。正确地使用索引能够显著的减少磁盘 I/O。  用户可以为一个表创建多个索引,只要不同索引使用的列或列的...
  • Oracle索引和事务

    2020-03-09 17:31:26
    Oracle索引和事务 1. 什么是索引?有什么用? 1.索引是数据库对象之一,用于加快数据的检索,类似于书籍的目录。在数据库中索引可以减少数据库程序查询结果时需要读取的数据量,类似于在书籍中我们利用索引可以不用...
  • Oracle提供了大量索引选项。知道在给定条件下使用哪个选项对于一个应用程序的性能来说非常重要。一个错误的选择可能会引发死锁,并导致数据库性能急剧下降或进程终止。而如果做出正确的选择,则可以合理使用资源,使...
  • 浅谈oracle索引

    2012-06-05 11:03:17
    oracle索引一般分为B树索引和位图索引,用的比较多的都是B树索引。  B树索引,比如普通索引,反转索引,降序索引,函数索引,这些索引都是B树索引,结构都是一样的,位图索引的存储结构和B树是不一样的,对于B树...
  • ORACLE索引与表一样,也属于段(segment)的一种。里面存放了用户的数据,跟表一样需要占用磁盘空间。只不过,在索引里的数据存放形式与表里的数据存放形式就不太一样了。在理解索引时,可以想象一本书,其中书...
  • oracle B*树索引原理学习

    千次阅读 2013-04-20 22:22:40
    B*Tree索引是最常见的索引结构,默认建立的索引就是这种类型的索引。B*Tree索引在检索高基数数据列(高基数数据列是指该列有很多不同的值)时提供了最好的性能。当取出的行数占总行数比例较小时B-Tree索引比全表检索...
  • 多维数据库(Multi Dimensional Database,MDD)使用Dimension(维度)和Cube(数据立方体、数据集市)模型描述数据。 多维数据模型 关系型数据库(Relational Database,RDB...下文讲解Oracle Essbase以及IBM Cogo...
  • 索引底层实现原理

    千次阅读 2017-05-26 17:03:44
    对数据库索引的关注从未淡出我的们的讨论,那么数据库索引是什么样的?聚集索引与非聚集索引有什么不同?希望本文对各位同仁有一定的帮助。有不少存疑的地方,诚心希望各位不吝赐教指正,共同进步。[最近首页之争...
  • Oracle索引详解

    2014-02-14 10:04:53
    From: http://www.2cto.com/database/201110/107271.html 一.索引介绍  1.1 索引的创建语法: CREATE UNIUQE | BITMAP INDEX .  ON .  ( | ASC | DESC,  | ASC | DESC,...)  TABLE
  • Oracle数据库底层

    千次阅读 2017-08-08 06:51:40
    Oracle底层的架构对编写出高性能的SQL语句非常重要 实例系统全局内存局部区域(SGA)和一系列的后台进程组成(PGA) SGA的两个领域:共享池和数据库数据缓冲 SGA共享池: 地位: 关键部分之一; 作用:Oracle...
  • Oracle 索引入门与提高

    2012-02-13 14:37:28
    Oracle数据库的接触算起来也有3年多了,刚学习时更多的是了解Oracle数据库的架构,慢慢的学习日常的基本管理工作。随着对Oracle数据库的不断深入,工作中涉及到一些数据库的调优问题,总的看下来,无非就是调内存...
  • Oracle 索引结构、内部管理

    千次阅读 2012-05-07 15:19:03
    摘要:本文对B树索引的结构、内部管理等方面做了一个全面的介绍。同时深入探讨了一些与B树索引有关的广为流传的说法,比如删除记录对索引的影响,定期重建索引能解决许多性能问题等。   1.B树索引的相关概念  ...
  • Oracle索引的内部结构

    2012-01-09 09:09:49
    Oracle 使用平衡树(B-tree)存储索引以便提升数据访问速度。当不使用索引时,用户必须对数据进行顺序扫描(sequential scan)来查找指定的值。如果有 n...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 16,947
精华内容 6,778
关键字:

oracle索引底层原理