页分裂:B+树的插入可能会引起数据页的分裂,删除可能会引起数据页的合并,二者都是比较重的IO消耗,所以比较好的方式是顺序插入数据,这也是我们一般使用自增主键的原因之一。
页分裂逆过程:页合并,当删除数据后,相邻的两个数据页利用率很低的时候会做数据页合并
主键索引:key:主键,value:数据页,存储每行数据
非主键索引:key:非主键索引,value:主键key,导致回表
最左匹配:优先将区分度高的列放到前面,这样可以高效索引,
最左匹配原则遇到范围查询就停止匹配,范围查询(>、<、between、like)为什么?因为出现范围匹配后,后面的索引字段无法保证有序,局部有序失去,顺序失去则无法提高查询效率
SELECT * FROM table WHERE a IN (1,2,3) and b >1
如何建立索引?
还是对(a,b)建立索引,因为IN在这里可以视为等值引用,不会中止索引匹配,所以还是(a,b)!
索引组织表
索引用页存储:key【10】-point【6】,通过调整key大小,当页大小固定的情况下,通过调整key大小,使得N叉树变化;
如key 10, point 6则单个索引16字节,页大小为16k,则页面总共可以存储1024个索引,即N大小
覆盖索引: 二级索引的信息已经存在想要的列,例如主键
如果现在有一个高频请求,要根据市民的身份z号查询他的姓名,这个联合索引就有意义了。它可以在这个高频请求上用到覆盖索引,不再需要回表查整行记录,减少语句的执行时间。
索引下推优化:可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。
整理索引碎片,重建表:alter table T engine=InnoDB
首先是看key的大小,另外是数据页的大小,如果需要改变N,则需要从这两个方面做改动;
一个innoDB引擎的表,数据量非常大,根据二级索引搜索会比主键搜索快,文章阐述的原因是主键索引和数据行在一起,非常大搜索慢,我的疑惑是:通过普通索引找到主键ID后,同样要跑一边主键索引,对于使用覆盖索引的情况下,使用覆盖索引可以直接解决问题
https://blog.csdn.net/itworld123/article/details/115144202
https://time.geekbang.org/column/article/69236
https://zhuanlan.zhihu.com/p/334684710
https://www.cxyzjd.com/article/pyzhizhuren/88431380
https://www.jianshu.com/p/4277d9dd0a9f
https://www.cnblogs.com/rjzheng/p/12557314.html
https://mengkang.net/1302.html
https://note.cser.club/database/bi-xu-le-jie-de-mysql-san-da-ri-zhi-binlogredo-log-he-undo-log
https://cloud.tencent.com/developer/news/44861
https://blog.csdn.net/weixin_43935927/article/details/109491334建立索引,要使用离散度(选择度)更高的字段。
我们先来看一个重要的属性列的 离散度,
count(distinct(column_name)) : count(*) -- 列的全部不同值个数:所有数据行行数
数据行数相同的情况下,分子越大,列的离散度就越高。简单来说,如果列的重复值越多,离散度就越低,重复值越少,离散度就越高。
当字段值比较长的时候,建立索引会消耗很多的空间,搜索起来也会很慢。我们可以通过截取字段的前面一部分内容建立索引,这个就叫前缀索引。
创建一张商户表,因为地址字段比较长,在地址字段上建立前缀索引
create table shop(address varchar(120) not null)
alter table shop add key(address(12)) // 截取12个字符作为前缀索引是最优的吗?
问题是,截取多少呢?截取得多了,达不到节省索引存储空间的目的,截取得少了,重复内容太多,字段的散列度(选择性)会降低。怎么计算不同的长度的选择性呢?
先看一下字段在全部数据中的选择度计算公式:
select count(distinct address) / count(*) from shop
select count(distinct left(address, n)) / count(*) as subn from shop
count(distinct left(address,n)) / count(*) 的结果是会随着 n 的变大而变大。举个例子,现在有两个address(东大街长兴小区,东大街福乐小区),那么 distinct(address,2) <distinct(address,3)
==>所以,截取的长度越长就会越接近字段在全部数据中的选择度
==>所以,我们要权衡索引大小和查询速度。
举个例子,通过不同长度去计算,与全表的选择性对比:
SELECT COUNT(DISTINCT(address))/COUNT(*) sub, -- 字段在全部数据中的选择度
COUNT(DISTINCT(LEFT(address,5)))/COUNT(*) sub5, -- 截取前5个字符的选择度
COUNT(DISTINCT(LEFT(address,7)))/COUNT(*) sub7,
COUNT(DISTINCT(LEFT(address,9)))/COUNT(*) sub9,
COUNT(DISTINCT(LEFT(address,10)))/COUNT(*) sub10, -- 截取前10个字符的选择度
COUNT(DISTINCT(LEFT(address,11)))/COUNT(*) sub11,
COUNT(DISTINCT(LEFT(address,12)))/COUNT(*) sub12,
COUNT(DISTINCT(LEFT(address,13)))/COUNT(*) sub13,
COUNT(DISTINCT(LEFT(address,15)))/COUNT(*) sub15
FROM shop
+--------+--------+--------+--------+--------+--------+--------+--------+--------+
| sub | sub5 | sub7 | sub9 | sub10 | sub11 | sub12 | sub13 | sub15 |
+--------+--------+--------+--------+--------+--------+--------+--------+--------+
| 0.9993 | 0.0225 | 0.4663 | 0.8618 | 0.9734 | 0.9914 | 0.9943 | 0.9943 | 0.9958 |
+--------+--------+--------+--------+--------+--------+--------+--------+--------+
可以看到在截取 11 个字段时 sub11(0.9993) 就已经很接近字段在全部数据中的选择度 sub(0.9958)了,而且长度也相较后面更短一些, 综合考虑比较合适。
ALTER TABLE shop ADD KEY (address(11))
1.索引的个数不要过多(浪费空间,更新变慢)
2.在用于 where 判断 order 排序和 join 的(on)字段上创建索引
3.区分度低的字段,例如性别,不要建索引(离散度太低,导致扫描行数过多)
4.更新频繁的值,不要作为主键或者索引(页分裂)
5.不建议用无序的值作为索引,例如身份z、UUID(在索引比较时需要转为ASCII,并且插入时可能造成页分裂)
6.若在多个字段都要创建索引的情况下,联合索引优于单值索引
7.联合索引把散列性高(区分度高)的值放在前面
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)