数据库基础(二)——索引(一)
- 为什么要使用索引
索引可以让我们避免权标扫描,提高查找效率。 - 什么样的信息能成为索引
主键、唯一键以及普通键等,只要能让数据具备一定的区分性。 - 索引的数据结构
B+树(主流)
Hash索引(InnoDB存储引擎 是支持hash索引的,不过,我们必须启用,hash索引的创建由InnoDB存储引擎引擎自动优化创建,我们干预不了。)
BitMap(位图索引,MySQL不支持,Oracle支持) - B树(也可以写作B-Tree,主要这里的-没有具体含义,也就是说,不存在B减树),B树可以通过合并、分裂、上移、下移节点来保持特征。
定义:- 根节点至少包括两个孩子(有几个孩子就是几阶B-Tree);
- 树的每个节点最多含有m个孩子(m>=2);
- 除了根节点和叶子节点外,其他每个节点至少有ceil(m/2)个孩子(ceil是向上取整);
- 所有叶子结点都位于同一层(即叶子结点的高度都是一样的);
- 假设每个非终端节点中包含n个非关键字信息,其中
a. k(i) (i = 1…n)为关键字,且关键字按顺序升序排序k(i - 1) < k(i);
b. 关键字的个数n必须满足:[ceil(m/2) - 1] <= n <= m - 1;(关于这一点,可以看下图,其中m取3,因为每个节点都有3个孩子,那m - 1等于2,ceil(m/2) - 1等于1,该树的关键字个数n取得是2,根节点的17和35就是关键字)
c. 非叶子节点的指针:P[1],P[2]…P[m];其中P[1]指向关键字小于k[1]的子树,P[m]指向关键字大于本节点中k[m - 1]的子树,其他的P[i]指向关键字属于(k[i - 1],k[i]]的子树。
- B+树(也写作B±tree,同理“-”是无意义的)
B+树是B树的变体,其定义基本上和B树相同,除了:
a. 非叶子节点的子树指针与关键字的个数相同;(这表明B+树可以存储更多关键字,这样的树更矮,查询效率更高)
b. 非叶子节点的子树指针P[i],指向关键字值[k[i],k[i + 1])的子树;
c. 非叶子节仅用来做索引,数据都保存在叶子街子节点中;
d. 所有的叶子节点均有一个链指针,用来指向下一个叶子节点(可以方便在叶子节点作范围统计,即一旦定位某个叶子节点,则可以从叶子节点开始,横向地跨子树去做统计)。
结论:B+树更适合用来做存储索引,原因如下:
- B+树的磁盘读写代价更低;
- B+树的查询效率更加稳定(O(logn));
- B+树更有利于对数据库做扫描。
-
理论上Hash索引的查询效率高于B+树,但是Hash索引存在以下缺陷,这导致它不是主流的索引
a. Hash索引仅仅能满足“=”,“IN”,不能做范围查询;
b. 无法用来避免数据的排序操作;
c. 不能利用部分索引键查询(B+树支持组合索引中的部分索引);
d. 不能避免表扫描;
e. 当遇到大量Hash值相等的情况后(Hash冲突),性能不一定会比B+树好。 -
除了B+树和Hash索引,还有BitMap(位图索引),目前使用BitMap的数据库并不多,比较主流的是Oracle。BitMap的结构有些类似B+树。
BitMap的缺陷:其锁的粒度非常大,所以并不适合高并发的联机事物处理系统,只适用于并发较少,统计较多的系统。 -
密集索引和稀疏索引的区别
定义:
密集索引文件中的每个搜索码值都对应一个索引值;
稀疏索引文件只为索引码的某些值建立索引项。可以这样理解:
- 密集索引文件中的每一个搜索码值都对应着一个索引值,这就可以理解为叶子结点不但需要保存键值,还保存位于同一行记录的其他列信息。由于密集索引决定了表的物理排列顺序,一个表只有一个物理排列顺序,所以一个表只能创建一个密集索引。
- 稀疏索引文件中只为搜索码的某些值建立索引项,这可以理解为叶子结点只保存了键位信息以及该行数据的地址,有的稀疏索引只保存了键位信息主键。
在MyISAM与InnoDB中的区别:
MyISAM:
在MyISAM中,不管是主键索引、唯一键索引、普通索引,其索引都属于稀疏索引;InnoDB:
在Innodb中 有且仅有一个密集索引
Innodb中选取规则:
(1)、如果一个主键被定义了 则该主键作为密集索引
(2)、若该主键没有被定义 则该表的第一个唯一非空索引作为密集索引
(3)、若不满足上述条件 则innodb内部会生成一个隐藏主键(密集索引)
(4)、非主键索引存储相关键位和其对应的主键值 包含两次查找 -
Mysql各种索引区别:
普通索引:最基本的索引,没有任何限制。
唯一索引:与"普通索引"类似,不同的就是:索引列的值必须唯一,但允许有空值。
主键索引:它 是一种特殊的唯一索引,不允许有空值。
全文索引:仅可用于 MyISAM 表,针对较大的数据,生成全文索引很耗时好空间。
组合索引:为了更多的提高mysql效率可建立组合索引,遵循”最左前缀“原则。 -
如何定位并优化慢查询SQL
思路:- 根据慢日志定位慢查询SQL;
- 使用explain等工具分析SQL;
- 修改SQL或者让SQL走索引。
-
联合索引的最左匹配原则的成因
- 最左前缀匹配原则,非常重要的原则, MySQL会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a =3 and b =4 and c> 5 and d=6如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到, a,b,d的顺序可以任意调整。
- =和in可以乱序,比如a = 1 and b =2 and c=3建立(a,b,c)索引可以任意顺序, MySQL的查询优化器会帮你优化成索引可以识别的形式。(就是说,不管人为地改变顺序,MySQL会自动先走a的索引)
- 成因:
MySQL创建复合索引的规则是首先会对复合索引的最左边,也就是索引中的第一个字段进行排序,在第一个字段排序的基础上,在对索引上第二个字段进行排序,其实就像是实现类似order by 字段1,字段2这样的排序规则,那么第一个字段是绝对有序的,而第二个字段就是无序的了,因此一般情况下直接只用第二个字段判断是用不到索引的,这就是为什么mysql要强调联合索引最左匹配原则的原因。
- 为什么要使用联合索引
- 减少开销。建一个联合索引(col1,col2,col3),实际相当于建了(col1),(col1,col2),(col1,col2,col3)三个索引。每多一个索引,都会增加写操作的开销和磁盘空间的开销。对于大量数据的表,使用联合索引会大大的减少开销!
- 覆盖索引。对联合索引(col1,col2,col3),如果有如下的sql: select col1,col2,col3 from test where col1=1 and col2=2。那么MySQL可以直接通过遍历索引取得数据,而无需回表,这减少了很多的随机io操作。减少io操作,特别的随机io其实是dba主要的优化策略。所以,在真正的实际应用中,覆盖索引是主要的提升性能的优化手段之一。
- 效率高。索引列越多,通过索引筛选出的数据越少。有1000W条数据的表,有如下sql:select from table where col1=1 and col2=2 and col3=3,假设假设每个条件可以筛选出10%的数据,如果只有单值索引,那么通过该索引能筛选出1000W10%=100w条数据,然后再回表从100w条数据中找到符合col2=2 and col3= 3的数据,然后再排序,再分页;如果是联合索引,通过索引筛选出1000w10%*10%*10%=1w,效率提升可想而知!
- 索引是建立得越多越好吗
不是,原因如下:- 数据量小的表不需要建立索引,建立索引会增加额外的索引开销;
- 数据变更需要维护索引,因此更多的索引意味着更多的维护成本;
- 更多的索引意味着也需要更多的空间。