@(数据库)[MySQL]html
数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询,更新数据库表中数据。
有两种基本的索引类型
顺序索引:基于值的顺序排序
散列索引:基于将值平均分布在若干散列桶中,一个值所属的散列通是有一个函数决定的,该函数被称为 散列函数
顺序索引中,根据包含记录是否按照搜索码制定的顺序排序能够分为汇集索引和非汇集索引mysql
聚簇索引和非聚簇索引并非单独的索引类型,而是一种数据存储方式 [高性能 MySQL]
索引的缺点主要是针对不合理索引而言的,对于开发者而言,索引维护所耗费的资源和索引所提供的快速查询能力节省的时间资源二者进行取舍。
MySQL 存储索引的时候通常咱们没有明确之处其他结构就是指的是 B-Tree 数据结构存储索引。 参考资料卫星数据:指的是索引元素所指向的数据记录,好比数据库的某一行。算法
什么是 B-Tree?一个 m 阶的 B 树有如下几个特征。sql
模拟查找文件29的过程:(1) 根据根结点指针找到文件目录的根磁盘块1,将其中的信息导入内存。【磁盘IO操做1次】数据库
(2) 此时内存中有两个文件名17,35和三个存储其余磁盘页面地址的数据。根据算法咱们发现17<29<35,所以咱们找到指针p2。服务器
(3) 根据p2指针,咱们定位到磁盘块3,并将其中的信息导入内存。【磁盘IO操做2次】数据结构
(4) 此时内存中有两个文件名26,30和三个存储其余磁盘页面地址的数据。根据算法咱们发现26<29<30,所以咱们找到指针p2。函数
(5) 根据p2指针,咱们定位到磁盘块8,并将其中的信息导入内存。【磁盘IO操做3次】性能
(6) 此时内存中有两个文件名28,29。根据算法咱们查找到文件29,并定位了该文件内存的磁盘地址。大数据
分析上面的过程,发现须要3次磁盘IO操做和3次内存查找操做。关于内存中的文件名查找,因为是一个有序表结构,能够利用折半查找提升效率。至于3次磁盘IO操做时影响整个B-tree查找效率的决定因素。
固然,若是咱们使用平衡二叉树的磁盘存储结构来进行查找,磁盘IO操做最少4次,最多5次。并且文件越多,B-tree比平衡二叉树所用的磁盘IO操做次数将越少,效率也越高。
B 树中每一个节点都具备卫星数据
插入(insert)操做:插入一个元素时,首先在B-tree中是否存在,若是不存在,即在叶子结点处结束,而后在叶子结点中插入该新的元素,注意:若是叶子结点空间足够,这里须要向右移动该叶子结点中大于新插入关键字的元素,若是空间满了以至没有足够的空间去添加新的元素,则将该结点进行“分裂”,将一半数量的关键字元素分裂到新的其相邻右结点中,中间关键字元素上移到父结点中(固然,若是父结点空间满了,也一样须要“分裂”操做),并且当结点中关键元素向右移动了,相关的指针也须要向右移。若是在根结点插入新元素,空间满了,则进行分裂操做,这样原来的根结点中的中间关键字元素向上移动到新的根结点中,所以致使树的高度增长一层。
例:自顶向下查找4的节点位置,发现4应当插入到节点元素3,5之间
节点3,5已是两元素节点,没法再增长。父亲节点 2, 6 也是两元素节点,也没法再增长。根节点9是单元素节点,能够升级为两元素节点。因而拆分节点3,5与节点2,6,让根节点9升级为两元素节点4,9。节点6独立为根节点的第二个孩子
删除(delete)操做:首先查找B-tree中需删除的元素,若是该元素在B-tree中存在,则将该元素在其结点中进行删除,若是删除该元素后,首先判断该元素是否有左右孩子结点,若是有,则上移孩子结点中的某相近元素到父节点中,而后是移动以后的状况;若是没有,直接删除后,移动以后的状况.。删除元素,移动相应元素以后,若是某结点中元素数目小于ceil(m/2)-1,则须要看其某相邻兄弟结点是否丰满(结点中元素个数大于ceil(m/2)-1),若是丰满,则向父节点借一个元素来知足条件;若是其相邻兄弟都刚脱贫,即借了以后其结点数目小于ceil(m/2)-1,则该结点与其相邻的某一兄弟结点进行“合并”成一个结点,以此来知足条件。那我们经过下面实例来详细了解吧。
例:删除11节点
删除11后,节点12只有一个孩子,不符合B树规范。所以找出12,13,15三个节点的中位数13,取代节点12,而节点12自身下移成为第一个孩子。(这个过程称为左旋)
B+Tree 是对于 B-Tree 的一种变体,有着比 B-Tree 更高的查询效率。
一个 m 阶的 B 树有着以下特色
根节点的最大元素等荣誉整个树的最大元素,叶子节点包含了全量元素信息,而且每个叶子节点都带有指向下一个节点的指针,造成了一个有序链表.
在 B+Tree 树中,只有叶子节点保存卫星数据.
须要补充的是,在数据库的汇集索引(Clustered Index)中,叶子节点直接包含卫星数据。在非汇集索引(NonClustered Index)中,叶子节点带有指向卫星数据的指针。
因为 B+Tree 树的中间节点没有卫星数据,因此一样大小的磁盘也(1~4K)能够容纳更多的元素,意味着查询的 IO 次数越少。
另外,B+Tree 的查询必须最终查询到叶子节点,和 B-Tree 不一样,查询性能最稳定,并且在范围查询中,比起只能以来繁琐的中序遍历的 B 树,更有效率。
综合来看,B+Tree 对比 B-Tree 有三大优点:
关于哈希索引,目前 MySQL 中只有 Memory 和 NDB 两种引擎支持,详细了解能够参考这篇文章 MySQL索引之哈希索引,本文不在赘述。
理解了索引的数据结构以后咱们就理解了索引在建立和使用上的一些方法(如下所描述的索引均指的是 B-Tree 索引)。
create table People ( last_name varchar(50) not null, first_name varchar(50) not null, dob date not null, gendar enum('m','f') not null, key(last_name, first_name, dob) );
select * from People where last_name = 'Allen' and first_name = 'Cuba' and dob = '1999-01-01';
select * from People where last_name = 'Allen';
select * from People where last_name like 'A%';
select * from People where last_name > 'Allen' and last_name < 'Bob';
select * from People where last_name = 'Allen' and last_name like 'B%';
只访问索引的查询
select last_name,
first_name, dob
from People
where last_name = 'Allen'
and first_name = 'Cuba' and dob = '1999-01-01';
select * from People where first_name = 'Allen';
select * from People where last_name = 'Allen' and dob = '1999-01-01';
select * from People where last_name = 'Allen' and first_name like 'J%' and dob = '1999-01-01';
- 最左前缀匹配原则,很是重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就中止匹配,好比a = 1 and b = 2 and c > 3 and d = 4 若是创建(a,b,c,d)顺序的索引,d是用不到索引的,若是创建(a,b,d,c)的索引则均可以用到,a,b,d的顺序能够任意调整。
- 使用独立的列
- 多列索引:MySQL 从5.0以后的更新版本引入了一种叫索引合并的策略,关于这项策略能够参考MySQL 优化之 index merge
- =和in能够乱序,好比a = 1 and b = 2 and c = 3 创建(a,b,c)索引能够任意顺序,mysql的查询优化器会帮你优化成索引能够识别的形式
- 尽可能选择区分度高的列做为索引,区分度的公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大咱们扫描的记录数越少,惟一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0,那可能有人会问,这个比例有什么经验值吗?使用场景不一样,这个值也很难肯定,通常须要join的字段咱们都要求是0.1以上,即平均1条扫描10条记录
- 索引列不能参与计算,保持列“干净”,好比from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,缘由很简单,b+树中存的都是数据表中的字段值,但进行检索时,须要把全部元素都应用函数才能比较,显然成本太大。因此语句应该写成create_time = unix_timestamp(’2014-05-29’);
- 尽可能的扩展索引,不要新建索引。好比表中已经有a的索引,如今要加(a,b)的索引,那么只须要修改原来的索引便可
一些有价值的参考资料