当前位置: 首页 > news >正文

B+树索引(13)之索引挑选(下)

B+树索引(12)之索引挑选(下)

前言回顾

上篇文章简单聊了索引选择的几点如

  • 只为搜索、排序、分组相关列建立索引,即使是显示列(select)也不考虑。

  • 尽量避免为基数太小的列建立索引,区分度太低索引可能不生效(如性别字段最多只有男、女、其它三种值,区分度太低)。

  • 索引列尽可能的少占用空间,特别是主键索引因为占用空间太多将影响聚簇索引、二级索引的存储和搜索效率。

文章链接参考

B+树索引(11)之索引挑选(上)

这篇文章是对索引挑选进行一个补充。

适量的使用前缀索引

如果我们的数据表字符集选择uft8,这就意味着一个字符需要采用1~3个字节编码,如果字符串够长那么将占用大量的内存空间,而数据页固定大小一般为16k那么索引列越长一个数据页中所能存储的记录就越少,那么搜索时可能需要消耗更多的性能在磁盘IO以及查找数据页上。

所以我们可以考虑存储部分字符串,这就是前缀索引,前缀索引虽然可以减少索引列的长度,但一定需要注意的一个问题就是前缀索引的选择性,只有前缀索引的选择性趋近完整列的选择性才是最佳的。

前缀索引使用

alter table table_name add index index_name(column_name(prefix_length));

前缀索引的缺点

前缀索引的优点肯定就是减少索引的存储长度,节省空间,但同样不能忽略的是它的缺点。

  • 使用前缀索引在匹配值后会去回表到聚簇索引中再次查询,所以索引覆盖对前缀索引无效。

  • 前缀索引只是对指定列的部分字符串排序,那么对于order by排序和group by分组语句都不生效。

具体前缀索引的介绍可以参考

B+树索引(12)之索引前缀

索引列需要单独出现

在使用索引时不应该给索引加任何修饰(函数也是类似),不然索引会失效,如下

select * from test_index where column_name * 2 < 4;

select * from test_index where column_name < 4 / 2;

两条语句的效果是一样,但是执行效率却是不同,第二条SQL的效率要高于第一条,因为第一条SQL是存储引擎遍历所有记录将每个column_name值都乘2再来比较结果值是否大于4,走了全表扫描,而第二条语句是单纯判断索引。

隐式类型转换

这里还需要注意一种常见情况,索引列隐式类型转换!

例如存在如下表

CREATE TABLE student_int (
  id tinyint(4) NOT NULL AUTO_INCREMENT COMMENT 'id',
  sno varchar(20) DEFAULT NULL COMMENT '学号',
  sname varchar(10) DEFAULT NULL COMMENT '学生姓名',
  PRIMARY KEY (`id`),
  KEY `index_sno` (`sno`)
) ENGINE=InnoDB AUTO_INCREMENT=127 DEFAULT CHARSET=utf8

同时存在如下测试数据

mysql> select * from student_int;
+-----+------+-------+
| id  | sno  | sname |
+-----+------+-------+
|   1 | 1001 | test  |
| 127 | 1001 | test  |
+-----+------+-------+
2 rows in set (0.00 sec)

如果存在如下查询语句

 select * from student_int where sno='1001';
 
 select * from student_int where sno=1001;

那么查询结果是多少呢?显然可以查出两条数据

但是为什么sno为varchar类型却能用int类型去比较呢?这就涉及到了索引列的隐式类型转换,当索引列name搜索的条件为sno=1001那么会将name列进行类型转换后再比较,所以不会走索引,如下所示。

主键插入顺序

我们知道聚簇索引会根据主键进行排序(记录与记录之间会按主键顺序排序,数据页与数据页间也会按主键顺序排序),但如果插入数据库的主键大小忽大忽小,就可能造成页的分裂和记录移位(当插入的记录主键值在一个已满数据页之间时,Mysql会将本数据页裂分为两个数据页,将本页的数据一部分移动到新数据页中,当插入记录主键值在一个未满的数据页之间时,那么会发生记录移位才能将新纪录插入到数据页单向链表中),这样显然会造成性能损耗,所以正确的做法是给主键设置自增长值(也就是AUTO_INCREMENT),让主键索引的记录都是往后面追加尽量减少数据页的裂分和记录位移带来的性能消耗。

相关文章:

  • 每日leetcode[回文数】
  • 线性代数贯串全书各章节的隐含关系(以秩为中心)
  • ​二进制运算符:(与运算)、|(或运算)、~(取反运算)、^(异或运算)、位移运算符​
  • 算法--分隔链表(Kotlin)
  • Postgresql查询执行模块README笔记
  • 【二叉树】最大二叉树 II
  • java毕业设计小说网站mybatis+源码+调试部署+系统+数据库+lw
  • 【每日一题】 和为 K 的子数组
  • 【初认Redis】
  • HTTP之Hop-by-hop首部
  • 指标体系搭建-专项1
  • 尚好房 10_Spring Security
  • JDK RMI探索与使用--序列化
  • Self-supervised Low Light Image Enhancement and Denoising 论文阅读笔记
  • hive窗口函数(开窗函数)
  • 07.Android之多媒体问题
  • android图片蒙层
  • Babel配置的不完全指南
  • dva中组件的懒加载
  • EOS是什么
  • iOS动画编程-View动画[ 1 ] 基础View动画
  • Python 反序列化安全问题(二)
  • python大佬养成计划----difflib模块
  • Python学习之路16-使用API
  • Vim Clutch | 面向脚踏板编程……
  • 从PHP迁移至Golang - 基础篇
  • 浏览器缓存机制分析
  • 如何胜任知名企业的商业数据分析师?
  • 学习笔记TF060:图像语音结合,看图说话
  • 源码之下无秘密 ── 做最好的 Netty 源码分析教程
  • 找一份好的前端工作,起点很重要
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • 走向全栈之MongoDB的使用
  • 看到一个关于网页设计的文章分享过来!大家看看!
  • Redis4.x新特性 -- 萌萌的MEMORY DOCTOR
  • 如何在 Intellij IDEA 更高效地将应用部署到容器服务 Kubernetes ...
  • ​ArcGIS Pro 如何批量删除字段
  • ​iOS安全加固方法及实现
  • (AngularJS)Angular 控制器之间通信初探
  • (C语言)fread与fwrite详解
  • (c语言版)滑动窗口 给定一个字符串,只包含字母和数字,按要求找出字符串中的最长(连续)子串的长度
  • (delphi11最新学习资料) Object Pascal 学习笔记---第2章第五节(日期和时间)
  • (done) NLP “bag-of-words“ 方法 (带有二元分类和多元分类两个例子)词袋模型、BoW
  • (Redis使用系列) Springboot 实现Redis 同数据源动态切换db 八
  • (十八)三元表达式和列表解析
  • (一)基于IDEA的JAVA基础12
  • (转)LINQ之路
  • .Family_物联网
  • .net core MVC 通过 Filters 过滤器拦截请求及响应内容
  • .NET中winform传递参数至Url并获得返回值或文件
  • .sys文件乱码_python vscode输出乱码
  • /deep/和 >>>以及 ::v-deep 三者的区别
  • /var/lib/dpkg/lock 锁定问题
  • @converter 只能用mysql吗_python-MySQLConverter对象没有mysql-connector属性’...
  • @property括号内属性讲解