MySQL索引简介
一种优化查询的数据结构,比如Mysql中的索引是用B+树实现的,而B+树就是一种数据结构,可以优化查询速度,可以利用索引快速查找数据,所以能优化查询。以文件的方式存储到磁盘。
b+树优势:b+树高度恒定(可以控制在3到5层),即渐进复杂的恒定,意味着检索是只需要进行几步读取即可。
b+树和b树的比较
1.BTree每个节点都可以存储数据,而B+Tree只有叶子节点才存储数据
2.B+Tree在mysql的实现时还做了定制,可以看到相邻的叶子节点间加了链式的关联的。意味着比如id>1检索,找到1后可以通过链式关联快速继续往下查找
mysql两种数据结构如何设计索引
MyISAM:索引文件数据文件分开存在,检索是先判断是否有索引,有则先到索引文件找到对于数据的逻辑地址,再去数据文件检索对应数据
InnoDB:数据就是一颗B+Tree(也可以理解为索引文件和数据文件在一起)。默认会以主键来创建一个索引,如果创建表时没有指定主键,InnoDB会为你指定一列不重复数据的列作为主键,如果找不到这样的列,那么InnoDB会给你生成一列作为主键(相当于Mongodb 中的 objectId策略)
影响因素
那么mysql数据库如何使用这些索引的,首先mysql会将索引加载到内存中(对于innodb引擎,我们可以认为也会加载数据),而这个能加载多少是由:innodb_buffer_pool_size决定,因此原则上这个值越大越好,但也不能大到超过机器内存。那么被加载的数据会已page形式存放到缓存池中,默认一个page为16k。系统利用LRU算法将缓存池中的数据进行淘汰,所以我们要十分注意innodb_buffer_pool_size的值,我们可以通过show status like "Innodb_buffer_pool_%";查看InnoDB的Buffer Pool情况,其中包括索引命中率,例如:
总共有8191 个page, 有7303 个是Free 状态, 有788个page 有数据,read 请求31569次,其中有710次请求使用物理磁盘获取
InnoDB Buffer Pool 的Read 命中率大概: (31569-710)/ 31569 * 100% = 97.75%,如果我们命中率低于了95%表示我们数据库索引需要进行优化,因为存在大量的IO读写工作。
其中我们十分需要注意数据表和innodb_buffer_pool_size的大小,因为当我们加载数据大于该值后,数据性能会急剧下降。
其中:
Innodb_buffer_pool_pages_data:InnoDB缓冲池中包含数据的页数。 该数字包括脏页面和干净页面。 使用压缩表时,报告的Innodb_buffer_pool_pages_data值可能大于Innodb_buffer_pool_pages_total(Bug#59550)。
Innodb_buffer_pool_pages_dirty:显示在内存中修改但尚未写入数据文件的InnoDB缓冲池数据页的数量(脏页刷新)。
Innodb_buffer_pool_pages_flushed:表示从InnoDB缓冲池中刷新脏页的请求数。
Innodb_buffer_pool_pages_free:显示InnoDB缓冲池中的空闲页面
Innodb_buffer_pool_pages_misc:InnoDB缓冲池中的页面数量很多,因为它们已被分配用于管理开销,例如行锁或自适应哈希索引。此值也可以计算为Innodb_buffer_pool_pages_total - Innodb_buffer_pool_pages_free - Innodb_buffer_pool_pages_data。
Innodb_buffer_pool_pages_total:InnoDB缓冲池的总大小,以page为单位。
innodb_buffer_pool_reads:表示InnoDB缓冲池无法满足的请求数。需要从磁盘中读取。
innodb_buffer_pool_read_requests:它表示从内存中逻辑读取的请求数。
innodb_buffer_pool_wait_free:通常,对InnoDB缓冲池的写入发生在后台。 当InnoDB需要读取或创建页面并且没有可用的干净页面时,InnoDB首先刷新一些脏页并等待该操作完成。 此计数器计算这些等待的实例。 如果已正确设置innodb_buffer_pool_size,则此值应该很小。如果大于0,则表示InnoDb缓冲池太小。
innodb_buffer_pool_write_request:表示对缓冲池执行的写入次数。
索引优化
1.语句判断分析
基于sql判断是否需要索引优化,我们可以在sql语句前加Explain来判断当前语句,示例:
EXPLAIN SELECT * FROM country_hotpoint_scene c WHERE c.cluster_type = "countryHotpoint" AND c.data_version = 1 AND c.cluster_code = "001" AND c.task_id != "1776630" AND ( c.cr_time BETWEEN "2020-04-30 00:00:00" AND "2020-04-30 23:59:59" )
通过type我们可以看到,现在进行的是全表检索。这时我们就可以考虑索引优化了
注:explain相关可以参考:https://www.cnblogs.com/tufujie/p/9413852.html
2.辨识度判断
我们要明白,索引选择性约稿效率有高。对于内容比较长的字段,我们没有必要保存完整的内容到索引当中,所以我们可以使用前缀索引即可(注意,前缀索引要求前面的辨识度非常高,如果辨识度在长度为一半时还达不到0.846就没必要做这个了)。但具体截取多少呢,我们利用:
SELECT COUNT(DISTINCT last_name)/COUNT(*)FROM people;进行计算,一般来讲0.846即可。同样的,对于组合索引,顺序也是根据选择性来,例如:
3.索引基本概念
1、需要加索引的字段,要在where条件中
2、数据量少的字段不需要加索引(即辨识度)
3、如果where条件中是OR关系,加索引不起作用
4、符合最左原则
例子:
联合索引(a,b,c)使用a或者a或者a、b或a、b、c这3种可以进行查找,不支持b、c进行查找
使用联合索引(a,b,c)。其中这些条件可以可以乱序,因为mysql的sql优化器会优化这些代码
网友评论