1、请讲一下常见的SQL优化方法(至少10条)
1.尽量避免使用子查询
虽然在 mysql5.6 版本之后对 select 的子查询用 join关联方式 做了优化,但是update/delete子查询依然先查外表再查内表,当外表过大时查询速度会很慢;因此尽量避免使用子查询
2. 用IN替换OR
当数据量大时最好使用IN而不是OR,而当数据集连续时使用between而不是IN
3. 禁止不必要的Order By排序
Order By 操作在查询中可能会消耗大量的时间和资源,尤其是在涉及到大量数据的情况下
【注意:默认情况下 mysql 会对所有的GROUP BY的字段进行排序,最好指定ORDER BY NULL禁止排序】
4. 总和查询可以禁止union用union all
union会涉及排序增大资源消耗,因此当已知无重复数据时,合并数据用union all
5.避免随机取记录(指从数据库表中无特定顺序地获取一定数量的记录)
6.将多次插入换成批量Insert插入
INSERT INTO t(id, name) VALUES(1, 'aaa');
INSERT INTO t(id, name) VALUES(2, 'bbb');
INSERT INTO t(id, name) VALUES(3, 'ccc');
—>
INSERT INTO t(id, name) VALUES(1, 'aaa'),(2, 'bbb'),(3, 'ccc');
7. 只返回必要的列,用具体的字段代替 select * 语句
select * 会增加很多不必要的消耗,除在order by操作时,字段的多少不会影响效率
8.区分IN与exists
exists先查询外表,IN先执行子查询;因此IN适合外表大内表小的情况,exists适合外表小内表大的情况
9.尽量使用数字型字段
尽量避免将仅包含数值信息的字段设计为字符型,会降低查询和连接操作的性能。数据库引擎在处理查询和连接时,需要逐个比较字符串中的每个字符,会消耗较多的时间。而对于数字型字段,只需要进行一次比较就足够了
10.尽量避免向客户端返回大数据量
若数据量过大,应考虑相应业务是否合理
2、请讲一下MySQL数据库innodb引擎索引底层实现的原理及查找过程
innodb索引中主要包含主键索引和辅助键索引,它们都是通过B+Tree实现的。在使用主键进行数据查询时,通过主键索引找到对应的叶子节点,然后得到叶子节点上的数据;而通过辅助键索引查找数据时,首先找到叶子节点,得到对应的主键,然后再通过主键值作为查询条件到主键索引上找到对应的叶子节点得到数据。
3、请讲一下MySQL数据库innodb引擎与myisam引擎索引的区别
InnoDB | MyISAM | |
---|---|---|
事务 | 支持事务、回滚、事务安全和崩溃恢复 | 不支持,但查询速度更快 |
主键 | 如果没设置主键,自动生成 | 允许没有索引和主键 |
外键 | 支持 | 不支持 |
锁 | 支持行锁和表锁 | 支持表锁 |
全文索引 | 不支持(使用插件可支持) | 支持 |
行数 | 获取行数需要扫全表 | 保存了行数,可直接读取 |
总结:MyISAM更适合查询多过修改的场景,其他时候建议用InnoDB |
4、请大概讲一下MySQL索引在哪些情况下会失效(至少5条)
1.当根据某字段进行函数运算操作之后,索引失效
2.字符串类型字段使用时,不加引号,索引将失效3.如果仅仅是尾部模糊匹配,索引不会失效;如果是头部模糊匹配,索引失效
4.当or连接的条件,左右两侧字段任意一个没有索引时,索引失效
5.如果MySQL评估使用索引比全表更慢,则不使用索引
5、请你讲一下ArrayList和LinkedList的区别
ArrayList 基于动态数组实现,内部使用数组来存储数据,插入和删除操作性能较差,访问元素性能好,固定分配空间可能会导致内存浪费;
LinkedList 基于双向链表实现,插入和删除操作性能好,访问元素性能差,动态分配空间不会浪费内存,但是每个元素都需要额外存储前后元素的引用,因此占用更多内存空间;
6、请讲一下你知道的设计模式
1.单例模式:保证一个类只有一个实例,为这个实例提供一个全局访问节点
将默认构造函数设置为私有,新建一个公有静态构建方法作为构造函数,该方法会在最初调用构造函数创建对象,并将该对象保存在一个 私有静态成员变量中,此后所有对于该函数的调用都将返回这一缓存对象
注意:单例模式违反了单一职责原则,多线程下需要特殊处理
2.简单工厂模式:创建一个工厂类,根据传入的类型,创建不同的类并返回
注意:简单工厂模式违反了开闭原则
3.工厂方法模式:定义一个接口,创建不同类型的工厂类实现该接口,实现不同的创建逻辑
4.抽象工厂模式:就是相较于工厂方法模式接口中增加不同方法,从而能够创建不同产品
三种工厂模式可以理解成现实中的工厂,一个比一个规模大,能够制作更多不同的产品
5.观察者模式:创建一个主题对象,主题对象提供方法来注册、删除和通知观察者;观察者实现更新接口,接口中定义主题变化时需执行的操作;主题变化时通知所有注册的观察者,观察者执行相应的操作
6.建造者模式(生成器模式):定义并实现一个建造者类,在这个类中实现构建这个对象所需要的全部方法。再定义并实现一个导演类,把一个建造者类传给它,让它负责这些方法调用的逻辑次序和对象的组合,然后统一给客户端返回一个生成好的复杂对象
7.代理模式: 我想访问一个对象,但是这个对象出于多种考虑,比如细节复杂、需要控制访问、隐藏细节等,不能让别人直接使用,必须要使用一个中间层性质的代理类,对这个对象的所有访问都由这个代理类来完成。
7、单例模式中懒汉模式与饿汉模式的区别,为什么懒汉模式不是线程安全的
区别是懒汉模式首先在创建私有静态属性时就已经通过调用构造方法的方式将对象创建好了,在通过静态方法获取对象时直接返回该对象。而饱汉模式最开始是没有创建对象,只有等到第一次调用静态方法获取对象时才会去创建。
1.在多线程环境下,当多个线程同时访问懒汉模式的单例实例,如果实例尚未创建,它们可能会同时进入实例化的分支,导致多个实例被创建
2.非原子操作,懒汉模式的实例化通常会分为两步,首先检查实例是否已经创建,然后再进行实例化。
可以通过添加synchronized锁实现线程安全
8、JDK代理与CGLIB代理的区别
JDK代理与CGLIB代理是Java中实现代理的两种常用方式
JDK代理:
基于接口实现,被代理类必须实现一个接口
利用Java的反射机制,性能较CGLIB高
由Java标准库提供,不需额外依赖
CGLIB代理:
通过继承实现,可以代理类的所有方法,包括final方法
由于通过继承实现,涉及到生成子类、加载类,因此性能较差
CGLIB代理需要引入CGLIB库,需要增加项目的依赖
9、请讲一下你对IOC/DI的理解
控制反转(IOC)和依赖注入(DI)是面向对象编程中的两个重要概念,用于实现松耦合和更易于测试的代码
IOC:
控制反转是一种编程思想,它将对象的创建和控制从程序本身移到外部容器中,从而实现具有依赖关系对象之间的解耦,调用类只依赖接口不依赖具体的实现类
DI:
依赖注入是IOC的一种实现方式,通过构造函数、方法参数或属性将实例变量传入到一个对象中去