JAVA业务开发常见错误整理(7.数据库索引 8.判等问题)

朱晔《Java业务开发常见错误100例》课程学习整理

一、数据库索引

InnoDB存储数据

虽然数据存储在磁盘中,但处理是在内存中的,为了减少磁盘随机读取次数,InnoDB采用页而不是行的粒度来保存数据,即数据被分成若干页,以页为单位保存在磁盘中。InnoDB的页大小,一般是16K.。各个数据页组成一个双向链表,每个数据页中的记录按照主键顺序组成单向链表;每一个数据页中有一个页目录,方便按照逐渐查询记录。页目录通过槽把记录分成不同的小组,每个小组有若干条记录。通过槽我们可以采用二分法快速搜索,无需从最小记录开始遍历整个页中的记录链表。

聚簇索引和二级索引

B+树的特点

1.最底层的节点叫做叶子节点,用来存放数据

2.其他上层节点叫做非叶子节点,仅用来存放目录项,作为索引

3.非叶子节点分为不同层次,通过分层来降低每一层的搜索量

4.所有节点按照索引键大小排列,构成一个双向链表,加速范围查找

InnoDB使用B+树,既可以保存实际数据,也可以加速数据搜索,这就是聚簇索引,即将数据存储与索引一同存储。由于数据在物理上只会保存一份,因此包含实际数据的聚簇索引只能有一个。

InnoDB会自动使用主键(唯一定义一条记录的单个或多个字段)作为聚簇索引的索引键(如果没有主键,就选择第一个不包含NULL值的唯一列)

为了实现非主键字段的快速搜索,就引出了二级索引,也缴费聚簇索引、辅助索引

额外创建二级索引的代价

1.维护代价。创建N个二级索引,就需要再创建N棵B+树,新增数据是不仅要修改聚簇索引,还需要修改这N个二级索引,增加耗时。

2.空间代价。虽然二级,索引不保存原始数据,但要保存索引列的数据,所以会占用更多的空间。

3.回表代价。二级索引不保存原始数据,通过索引找到主键后需要再查询聚簇索引,才能得到最终的数据

如果需要查询的是索引列索引或连锁因能覆盖的数据,那么查询索引本身已经“覆盖”了需要的数据,不再需要回表查询。因此这种情况也叫作索引覆盖

索引开销最佳实践

1.无需一开始就建立索引,可以等到业务场景明确,或数据量超过1万、查询变慢后,再针对需要查询、排序或分组的字段创建索引,创建索引后可以通过EXPLAIN命令,确认查询是否使用索引

2.尽量索引轻量级的字段,比如能索引int字段就不索引varchar字段,索引字段也可以是部分前缀,在创建的时候指定字段索引长度。针对长文本的搜索,可以考虑使用ElasticSearch等专门用于文本搜索的索引数据库

3.尽量不要在SQL语句中SELECT*,而是SELECT必要的字段,甚至可以考虑使用联合索引来包含我们要搜索的字段,既能实现索引加速,又可以避免回表的开销

不是所有针对索引列的查询都能走索引

1.索引只能匹配列前缀。索引B+树中港数据按照索引值排序,只能那个根据前缀进行比较。如果只按照后缀搜索,可以把数据反过来存,用的时候再正过来

2.条件涉及函数操作无法走索引。索引保存的是索引列的原始值,而不是经过函数计算后的值。如果需要针对函数调用走数据库索引的话,只能保存一份函数变换后的值,然后重新针对这个计算列做索引

3.联合索引只能匹配左边的列。联合索引中,数据是按照索引第一列排序,第一列数据相同时才会按照第二列排序。因此如果我们想使用联合索引,查询条件的各个列必须是联合索引中从最左边开始连续的列

数据库基于成本决定是否走索引

MySQL 5.6及之后,我们可以使用optimizer trace功能查看优化器生成执行计划的过程

二、判等问题

注意==和equals区别

比较值的内容,除了基本类型只能使用==外,其他类型都需要使用equals

编译器默认情况下会缓存[-128,127]的数值,因此在这种情况下对直接赋值的变量使用==比较也会得到正确结果

Java字符串常量池机制,设计初衷是节省内存。当代码中出现双引号形式创建字符串对象时,JVM会先对这个字符串进行检查,如果字符串常量池中存在相同内容的字符串对象的引用,则将引用返回;否则创建新的字符串对象,然后将这个引用放入字符串常量池,并返回该引用。

使用new声明的字符串调用intern方法,也可以让字符串进行驻留,但在业务代码中滥用intern,可能会产生性能问题。因此不要轻易使用intern,如果使用要注意控制主流的字符串的数量,并留意常量表的各项指标

对于自定义的类型,如果需要判等,务必同时实现equals和hashCode方法,如果需要参与比较,请务必保持equals、hashCode、compareTo逻辑一致

Lombok的@EqualsAndHashCode注解实现equals和hashCode时,默认使用类型所有非static、非transient的字段,且不考虑父类可以通过@EqualsAndHashCode.Exclude修饰,排除某些字段,当类型之间有继承关系,并设置callSuper为true,来让子类的equals和hashCode调用父类的相应方法

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值