数据库专题(有关索引的问题)

tech2022-09-13  108

一,什么是数据库索引?

索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息。如果想按特定职员的姓来查找他或她,则与在表中搜索所有的行相比,索引有助于更快地获取信息。 索引的一个主要目的就是加快检索表中数据,亦即能协助信息搜索者尽快的找到符合限制条件的记录ID的辅助数据结构。 例如这样一个查询:select * from table1 where id=10000。如果没有索引,必须遍历整个表,直到ID等于10000的这一行被找到为止;有了索引之后(必须是在ID这一列上建立的索引),即可在索引中查找。由于索引是经过某种算法优化过的,因而查找次数要少的多。可见,索引是用来定位的。 从数据搜索实现的角度来看,索引也是另外一类文件/记录,它包含着可以指示出相关数据记录的各种记录。其中,每一索引都有一个相对应的搜索码,字符段的任意一个子集都能够形成一个搜索码。这样,索引就相当于所有数据目录项的一个集合,它能为既定的搜索码值的所有数据目录项提供定位所需的各种有效支持。

二,索引的类别

索引分为聚簇索引和非聚簇索引两种,聚簇索引 是按照数据存放的物理位置为顺序的,而非聚簇索引就不一样了;聚簇索引能提高多行检索的速度,而非聚簇索引对于单行的检索很快。 根据数据库的功能,可以在数据库设计器中创建三种索引:唯一索引、主键索引和聚集索引。

唯一索引 唯一索引是不允许其中任何两行具有相同索引值的索引。当现有数据中存在重复的键值时,大多数数据库不允许将新创建的唯一索引与表一起保存。数据库还可能防止添加将在表中创建重复键值的新数据。

主键索引 数据库表经常有一列或多列组合,其值唯一标识表中的每一行。该列称为表的主键。在数据库关系图中为表定义主键将自动创建主键索引,主键索引是唯一索引的特定类型。该索引要求主键中的每个值都唯一。当在查询中使用主键索引时,它还允许对数据的快速访问。

聚集索引 在聚集索引中,表中行的物理顺序与键值的逻辑(索引)顺序相同。一个表只能包含一个聚集索引。如果某索引不是聚集索引,则表中行的物理顺序与键值的逻辑顺序不匹配。与非聚集索引相比,聚集索引通常提供更快的数据访问速度。聚集索引和非聚集索引的区别,如字典默认按字母顺序排序,读者如知道某个字的读音可根据字母顺序快速定位。因此聚集索引和表的内容是在一起的。如读者需查询某个生僻字,则需按字典前面的索引,举例按偏旁进行定位,找到该字对应的页数,再打开对应页数找到该字。这种通过两个地方而查询到某个字的方式就如非聚集索引。 使用聚集索引的场合: A.某列包含了小数目的不同值。 B.排序和范围查找。

索引列 可以基于数据库表中的单列或多列创建索引。多列索引可以区分其中一列可能有相同值的行。如果经常同时搜索两列或多列或按两列或多列排序时,索引也很有帮助。例如,如果经常在同一查询中为姓和名两列设置判据,那么在这两列上创建多列索引将很有意义。

组合索引 基于多个字段而创建的索引就称为组合索引。 创建索引 create index idx1 on table1(col1,col2,col3) 查询select * from table1 where col1= A and col2= B and col3 = C

使用非聚集索引的场合: a.此列包含了大数目的不同值; b.频繁更新的列

聚集索引和非聚集索引的区别是什么,分别在什么情况下使用? 根本区别是表中记录的物理顺序和索引的排列顺 序是否一致。 聚集索引的表中记录的物理顺序与索引的排列顺序一致。 优点是查询速度快,因为一旦具有第一个索引值的记录被找到,具有连续索 引值的记录也一定物理的紧跟其后。 缺点是对表进行修改速度较慢,这是为了保持表中的记录的物理顺序与索引 的顺序一致,而把记录插入到数据页的相应位置,必须在数据页中进行数据重排,降低了执行速度。在插入新记录时数据文件为了维持 B+Tree 的特性而频繁的 分裂调整,十分低效。 其他方面的区别: 1.聚集索引和非聚集索引都采用了 B+树的结构,但非聚集索引的叶子层并 不与实际的数据页相重叠,而采用叶子层包含一个指向表中的记录在数据页中 的指针的方式。聚集索引的叶节点就是数据节点,而非聚集索引的叶节点仍然 是索引节点。 2.非聚集索引添加记录时,不会引起数据顺序的重组。

三,基本特点

建立索引的目的: 是加快对表中记录的查找或排序。为表设置索引要付出代价的:一是增加了数据库的存储空间,二是在插入和修改数据时要花费较多的时间(因为索引也要随之变动)。数据库索引就是为了提高表的搜索效率而对某些字段中的值建立的目录 。创建索引可以大大提高系统的性能。 第一,通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。 第二,可以大大加快数据的检索速度,这也是创建索引的最主要的原因。 第三,可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。 第四,在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。 第五,通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。

四,优点与缺点

1.优点: 通过建立索引可以极大地提高在数据库中获取所需信息的速度,同时还能提高服务器处理相关搜索请求的效率,从这个方面来看它具有以下优点: 极大加快数据的检索速度; 创建唯一性索引,保证数据库表中每一行数据的唯一性; 加速表和表之间的连接; 在使用分组和排序子句进行数据检索时,可以显著减少查询中分组和排序的时间 2.缺点: 需要占用物理空间 当对表中的数据进行增加、删除和修改,索引也要动态维护,降低数据的维护速度。

五,索引字段的选择

尽量选择区分度高的字段作为索引,区分度的公式是 count(distinct col)/count(*),表示 字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是 1,而一些状态、 性别字段可能在大数据面前区分度就是 0。在性别字段上增加索引,并不能明显加快检索 速度。

六,索引的实现原理

目前大部分数据库系统及文件系统都采用 B-Tree(B 树)或其变种 B+Tree (B+树)作为索引结构。B+Tree 是数据库系统实现索引的首选数据结构。 在 MySQL 中,索引属于存储引擎级别的概念,不同存储引擎对索引的实现方式 是不同的,本文主要讨论 MyISAM 和 InnoDB 两个存储引擎的索引实现方式。

MyISAM 索引实现 MyISAM 引擎使用 B+Tree 作为索引结构,叶节点的 data 域存放的是数据记录 的地址。下图是 MyISAM 索引的原理图: 这里设表一共有三列,假设我们以 Col1 为主键,则图 8 是一个 MyISAM 表的主 索引(Primary key)示意。可以看出 MyISAM 的索引文件仅仅保存数据记录的地址。 在 MyISAM 中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只 是主索引要求 key 是唯一的,而辅助索引的 key 可以重复。 如果我们在 Col2 上建立 一个辅助索引,则此索引的结构如下图所示: 同样也是一颗 B+Tree,data 域保存数据记录的地址。因此,MyISAM 中索引 检索的算法为首先按照 B+Tree 搜索算法搜索索引,如果指定的 Key 存在,则取出其 data 域的值,然后以 data 域的值为地址,读取相应数据记录。MyISAM 的索引方式也叫做“非聚集索引”,之所以这么称呼是为了与 InnoDB 的聚集索引区分。InnoDB 索引实现 虽然 InnoDB 也使用 B+Tree 作为索引结构,但具体实现方式却与 MyISAM 截 然不同。 1.第一个重大区别是 InnoDB 的数据文件本身就是索引文件 MyISAM 索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。而在 InnoDB 中,表数据文件本身就是按 B+Tree 组织的一个索引结构,这棵树的叶节点 data 域保存了完整的数据记录。 这个索引的 key 是数据表的主键,因此 InnoDB 表数据文件本身就是主索引。 上图是 InnoDB 主索引(同时也是数据文件)的示意图,可以看到叶节点包含了完整 的数据记录。这种索引叫做聚集索引。因为 InnoDB 的数据文件本身要按主键聚集。 1 .InnoDB 要求表必须有主键(MyISAM 可以没有),如果没有显式指定,则 MySQL 系统会自动选择一个可以唯一标识数据记录的列作为主键,如果不存在这种列,则 MySQL 自动为 InnoDB 表生成一个隐含字段作为主键,类型为长整形。在 InnoDB 上采用自增字段做表的主键。 非单调的主键会造成在插入新记录时数据文件为了维持 B+Tree 的特性而频繁的分裂调整,十分低效,而使用自增字段作为主键则是一个很好的选择。如果表使用 自增主键,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置,当 一页写满,就会自动开辟一个新的页。 2.第二个与 MyISAM 索引的不同是 InnoDB 的辅助索引data 域存储相应记录主键的值而不是地址。 聚集索引这种实现方式使得按主键的搜索十分高效,但是辅助索引搜索需要检索两遍索 引:首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。

InnoDB 使用的是聚簇索引,将主键组织到一棵 B+树中,而行数据就储存在叶子节 点上,若使用"where id = 14"这样的条件查找主键,则按照 B+树的检索算法即可查找到 对应的叶节点,之后获得行数据。若对 Name 列进行条件搜索,则需要两个步骤:第一步 在辅助索引 B+树中检索 Name,到达其叶子节点获取对应的主键。第二步使用主键在主 索引 B+树种再执行一次 B+树检索操作,最终到达叶子节点即可获取整行数据。 MyISM 使用的是非聚簇索引,非聚簇索引的两棵 B+树看上去没什么不同,节点 的结构完全一致只是存储的内容不同而已,主键索引 B+树的节点存储了主键,辅助键索引 B+树存储了辅助键。表数据存储在独立的地方,这两颗 B+树的叶子节点都使用一个地址 指向真正的表数据,对于表数据来说,这两个键没有任何差别。由于索引树是独立的,通 过辅助键检索无需访问主键的索引树。

为了更形象说明这两种索引的区别,我们假想一个表如下图存储了 4 行数据。其中 Id 作为主索引,Name 作为辅助索引。 b树的查找: 如图所示,如果要查找数据项 29,那么首先会把磁盘块 1 由磁盘加载到内存, 此时发生一次 IO,在内存中用二分查找确定 29 在 17 和 35 之间,锁定磁盘块 1 的 P2 指针,内存时间因为非常短(相比磁盘的 IO)可以忽略不计,通过磁盘块 1 的 P2 指 针的磁盘地址把磁盘块 3 由磁盘加载到内存,发生第二次 IO,29 在 26 和 30 之间, 锁定磁盘块 3 的 P2 指针,通过指针加载磁盘块 8 到内存,发生第三次 IO,同时内存 中做二分查找找到 29,结束查询,总计三次 IO。

当 b+树的数据项是复合的数据结构(建立的是复合索引),比如 (name,age,sex)的时候,b+树是按照从左到右的顺序来建立搜索树的,比如当(张 三,20,F)这样的数据来检索的时候,b+树会优先比较 name 来确定下一步的搜索方向, 如果 name 相同再依次比较 age 和 sex,最后得到检索的数据;但当(20,F)这样的没 有 name 的数据来的时候,b+树就不知道下一步该查哪个节点,因为建立搜索树的时 候 name 就是第一个比较因子,必须要先根据 name 来搜索才能知道下一步去哪里查 询。比如当(张三,F)这样的数据来检索时,b+树可以用 name 来指定搜索方向,但下 一个字段 age 的缺失,所以只能把名字等于张三的数据都找到,然后再匹配性别是 F 的数据了, 这个是非常重要的性质,即索引的最左匹配特性。注意:B+tree 多列索 引保存的顺序是按照索引创建的顺序,检索索引时按照此顺序检索。

七,Mysql 的 B+树索引的优点?为什么不用二叉树?B-树和 B+树为 什么比红黑树更合适?

数据库文件很大,需要存储到磁盘上,索引的结构组织要尽量减少查找过程中磁盘 I/O 的存取次数。 1.高度原因 B+树中的每个结点可以包含大量的关键字,这样树的深度降低了,所以任何关键 字的查找必须走一条从根结点到叶子结点的路,所有关键字查询的路径长度相同,导致 每一个数据的查询效率相当,这就意味着查找一个元素只要很少结点从外存磁盘中读入 内存,很快访问到要查找的数据,减少了磁盘 I/O 的存取次数。但是B-树的每个节点都有data域(指针),这无疑增大了节点大小,增加了磁盘IO次数(磁盘IO一次读出的数据量大小是固定的,单个数据变大,每次读出的就少,IO次数增多,一次IO多耗时)

优点一: B+树只有叶节点存放数据,其余节点用来索引,而B-树是每个索引节点都会有Data域。优点二: B+树所有的Data域在叶子节点,并且所有叶子节点之间都有一个链指针。 这样遍历叶子节点就能获得全部数据,这样就能进行区间访问啦。在数据库中基于范围的查询是非常频繁的,而B树不支持这样的遍历操作。

2.磁盘预读原理和局部性原理 将一个节点的大小设为等于一个页,这样每个节点只需要一次 I/O 就可以完全载入。

使用B+树和B树而不是用红黑树的原因: AVL 树(平衡二叉树)和红黑树(二叉查找树)基本都是存储在内存中才会使用的数据结构。在大规模数据存储的时候,红黑树往往出现由于树的深度过大而造成磁盘IO读写过于频繁,进而导致效率低下的情况。为什么会出现这样的情况,我们知道要获取磁盘上数据,必须先通过磁盘移动臂移动到数据所在的柱面,然后找到指定盘面,接着旋转盘面找到数据所在的磁道,最后对数据进行读写。磁盘IO代价主要花费在查找所需的柱面上,树的深度过大会造成磁盘IO频繁读写。根据磁盘查找存取的次数往往由树的高度所决定,所以,只要我们通过某种较好的树结构减少树的结构尽量减少树的高度,B树可以有多个子女,从几十到上千,可以降低树的高度。

八,建立索引的原则

1.最左前缀匹配原则 mysql 会一直向右匹配直到遇到范围查询(>、<、between、 like)就停止匹配,范围查询会导致组合索引半生效。 比如 a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,c 可 以用到索引,d 是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d 的顺序可以任意调整。where 范围查询要放在最后 (这不绝对,但可以利用一部分索引)。 特别注意:and 之间的部分可以乱序,比如 a = 1 and b = 2 and c = 3 建立(a,b,c) 索引可以任意顺序,mysql 的查询优化器会帮你优化成索引可以识别的形式。2.尽量选择区分度高的字段作为索引 某字段的区分度的公式是 count(distinct col)/count(*),表示字段不重复的比例,比例越大,我们扫描的记录数越少,查找匹配 的时候可以过滤更多的行,唯一索引的区分度是 1,而一些状态、性别字段可能在大数 据面前区分度就是 0。3.不在索引列做运算或者使用函数。4.尽量扩展索引,不要新建索引。比如表中已经有 a 的索引,现在要加(a,b)的索引,那 么只需要修改原来的索引即可。5.Where 子句中经常使用的字段应该创建索引, 分组字段或者排序字段应该创建索引, 两个表的连接字段应该创建索引。7.like 模糊查询中,右模糊查询(321%)会使用索引,而%321 和%321%会放弃索引 而使用全局扫描。

九,数据库索引失效的情况

1.对于组合索引,不是使用的第一部分,则不会使用索引 。 2.or 语句前后没有同时使用索引。要想使用 or,又想让索引生效,只能将 or 条件中的每个 列都加上索引。 3.如果列类型是字符串,那一定要在条件中使用引号引起来,否则不会使用索引 。 4.如果 mysql 估计使用全表描述比使用索引快,则不使用索引。 5.在索引列上做运算或者使用函数。 6.以“%”开头的 LIKE 查询,模糊匹配。

最新回复(0)