主键索引和次级索引

首先,索引是啥啊。
我不知道是不是外国人发明的,百度了一下,说是数据库术语。
数据库表呢,如果很大,你去查一个值,就得全表扫描。这很慢。
但是有个索引,就快多了,为啥呢?
这得先来看索引长啥样。

百度上说索引像目录一样,但是index明显和content不是一个意思啊。
index索引是说,一本书或者文档的重要词语,概念,资料。任何的文档都可以有索引。
content目录一般是有10页以上的文档需要,而且是书或者文档的一部分。所以TOC表示目录,table of contents。是按书中内容章节的先后顺序来的,并且标注页码。一般目录表最好不超过2页。
而索引index,是一些重要概念,可以有很多页。有文章参考,概念释义等。一般是按照字母排序,但是不按照出现在书中的顺序排序。一般在结尾,包括一些特定的词语,页码,引用文章的重要概念。重要的观点一般都有索引。
在这里插入图片描述
从索引的英文解释上看,实际索引是重要概念的指针。比如你有一本很厚的书,你只想找其中一个关键词,没有书后索引,你要翻遍全书,有了书后索引,你直接去索引里找这个关键词,然后通过页码指示去找书本相应内容。

但是索引页可能有5页。也就是说这个索引页是附加的。

回到数据库,索引表是独立于数据库表的。
也就是你要另外建一个数据库表的索引。
对于insert和update表的操作,你不仅仅是对表进行操作,同时还要重新写,并且排序索引表,如果你有两个索引表,那就要对三个表进行操作。就是说有主键索引和非主键索引(次级索引)。
如果表和索引都在一个地方,就会需要更多的时间。

为啥需要索引

数据以块存储在磁盘上(假设在磁盘上),那所有这些数据库就像链表一样被访问,就是自己存储一块,然后有个指针指向相邻的下一块(差不多这意思),既然是有连续的指针。不需要连续存储的。
对一个表,我们只能对一列进行排序。如果我们去查找没排序的字段,假设这个表有N个块,那线性搜索平均需要访问N/2块。最大是N块。因为需要不停对查找到的列做比较。这还是针对是主键(唯一键),如果你要查找的不是唯一键,那就得查找N块。
如果字段排序了,那就二分法查找。就只需要访问log2N块。
如果对非主键字段进行排序,那对比一个高值,其实就等于对比了很多个高值,所以就提升了很大的性能啊。

数据库索引是啥

从上面能看出来,数据库索引是对多个字段的记录值进行排序。 你建了一个表的某个字段(或多个字段)的索引,就是建了一个有字段值,和指向表中记录位置的指针的一个结构。这个指针结构会被排序。允许二分查找。
坏处就是,索引也占内存啊。
而且改了表,索引也要更新啊。

我们来看一个具体的表的例子:
假设表字段这样的:
字段名 | 数据类型 | 占磁盘空间

-------- | ----- | -----
ID(主键) | INT | 4 bytes
Name | char(50) | 50 bytes
Sex | char(50) | 50 bytes
Address | char(100) | 100 bytes

假定我们这个表有10000个固定大小的记录。
每条记录的长度就为204个字节,默认磁盘块大小是B=1024bytes,也就是一个磁盘块可以放1024/204=5条记录。要保存这个表记录需要10000/5=2000个磁盘块。

对ID进行线性查找需要平均2000/2=1000次访问。但是它是主键,所以可以进行二分查找,就只需要log2 (2000) = 10.9次访问。就11次。
如果你对非主键Name进行访问,那就得需要遍历2000次。

建个索引

所以咱对Name建个索引。
字段名 | 数据类型 | 占磁盘空间

-------- | ----- | -----
Name | char(50) | 50 bytes
pointer | special | 4 bytes

所以索引是54个字节。默认磁盘块1024个字节。所以每个磁盘块可以有18条记录。索引将要占用磁盘块10000/18 = 555.555个。
那么在这个索引上先找Name就需要一个二分查找,需要查找log2 (555.5) = 9次,就是要找9块磁盘块。然后在Name基础上查找Address就只需要再找一块,就是10块。

跟原先去找10000个相比,快多了。

啥时候建

这样一看,索引真好。但是别忘了,索引占用了555个磁盘块啊,对比表记录的2000个磁盘块,直接用上了25%还多的空间啊。
所以说,索引很占空间。 即使他能帮我们大大加快查找条目中的匹配字段,但是当你去执行插入或者删除操作的时候,弊端就来了。
所以,要考虑清楚用哪个字段来建。因为二分查找对数据唯一性的要求很高。另外这里还要考虑数据基数。也就表的列中的数据,特别是其中有多少个唯一值。到这里我又回去查了查数据库,因为我完全不记得什么基数,什么是目数。维基百科上讲cardinality是指数据库表中特定列(属性)中包含的数据值的唯一性。
那么联想到集合,集合<a,b,c>包含3个元素,集合的基数就是集合中元素的个数,也就是说这里的集合基数是3。
那我再延申一下,就是说这个基数那就是表中的一组行呀。
目数,是指表的属性列。
而这个基数呢,首先要考虑数据的唯一性,如果你这列的行值又很多重复的,就1,2,1,2,1,2这种的,那你的基数就是2,如果这列的行值全是唯一的,那你这基数就是行数。

回到正题索引上,如果你这列的值基数是2,那你就等于在查找数据的时候把整个数据表都一分为二了。如果你基数是1000,那就是找1000行。
这个意思就是说,如果你的列基数很低,那其实没必要建索引的。列基数高才要建索引。就算列基数高时,索引占空间,但是对查找帮助很大。如果列基数低,索引虽然占空间少,但是没啥必要。列基数低于行数的30%,也就是说10行里其实只有3个不同的值,那就没必要用索引。
一般在咱数据库表中,也不会用年月,数值等重复概率高的列做索引的。只会用ID,编号之类的。

其他要考虑的问题

就是之前提到的,你更新的表有一个索引,那就得实际上有两个写的操作,而且要重新排序index。如果表和索引都在一个硬盘上,那就得花费更多的时间。所以,如果你把表和索引放在不同的硬盘上,可以节省时间。
另一个问题就是这个数据不停的插入,导致索引的存储碎片。这时候需要reorganize。这个我还真不知道怎么搞呢。

索引占据空间和写操作。看你这个表是要经常写还是要经常读了。衡量是否需要建索引。

回到主题:主键索引和次级索引

主键就是基于主键列并且没有重复值的索引。
次级索引就是非主键索引,而且可以有重复值。

索引里面有两部分哈,一个是查找键,一个是数据参照。
查找键就是主键值或者其他列值,排了序的。数据参照包含个指针,存储了查找键在磁盘块上的地址。

主键索引

主键索引不是说只包含一列主键,而是说也可能是由很多列值,只是是组合值也是唯一的。
而且基于索引key是排序的。主键索引只能有一个。

次级索引

非主键索引,可以有重复值。
对行如何在数据块里组织的没啥影响。可以有好多个呢。

嗯,还是去看书了。。。

猜你喜欢

转载自blog.csdn.net/weixin_45689053/article/details/113345904