这是我整理网上的帖子,总结出来的常见面试题,做个记录
1.常见的运行时异常
ClassCastException(类转换异常)
IndexOutOfBoundsException(数组越界异常)
NullPointerException(空指针异常)
ArrayStoreException(数据存储异常,操作数组时类型不一致)
BufferOverflowException(还有IO操作的,缓冲溢出异常)
OutOfMemoryError(内存溢出异常)
ConcurrentModificationException (List遍历时删除新增元素异常)
IllegalArgumentException (非法参数异常)
2. 面向对象的特征有哪些方面?
- 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。
- 继承:继承是从已有类得到继承信息创建新类的过程。提供继承的类叫父类(超类、基类)、得到继承的类叫子类(派生类)。
- 封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。可以说,封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口(可以想想普通洗衣机和全自动洗衣机的差别,明显全自动洗衣机封装更好因此操作起来更简单;我们现在使用的智能手机也是封装得足够好的,因为几个按键就搞定了所有的事情)。
- 多态性:多态性是指允许不同子类型的对象对同一消息作出不同的响应。简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情。实现多态需要做两件事:1). 方法重写(子类继承父类并重写父类中的方法);2). 对象造型(用父类型引用引用子类型对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)
3. &和&&的区别
- &和&&都可以用作逻辑与的运算符,表示逻辑与(and),当运算符两边的表达式的结果都为true时,整个运算结果才为true,否则,只要有一方为false,则结果为false。
- &&还具有短路的功能,即如果第一个表达式为false,则不再计算第二个表达式,例如,对于if(str != null && !str.equals(“”))表达式,当str为null时,后面的表达式不会执行,所以不会出现NullPointerException。如果将&&改为&,则会抛出NullPointerException异常。If(x==33 & ++y>0) y会增长,If(x==33 && ++y>0)不会增长
- &还可以用作位运算符,当&操作符两边的表达式不是boolean类型时,&表示按位与操作,我们通常使用0x0f来与一个整数进行&运算,来获取该整数的最低4个bit位,例如,0x31 & 0x0f的结果为0x01
注意:逻辑或运算符(|)和短路或运算符(||)的差别也是如此。
4.解释内存中的栈(stack)、堆(heap)和静态区(static area)的用法
栈空间操作起来最快但是栈很小,通常大量的对象都是放在堆空间
String str = new String("hello");
上面的语句中变量str放在栈上,用new创建出来的字符串对象放在堆上,而”hello”这个字面量放在静态区。
5.Math 的四舍五入方法 rond()
Math.round(11.5) 等于多少?Math.round(-11.5)等于多少?
答:Math.round(11.5)的返回值是12,Math.round(-11.5)的返回值是-11。四舍五入的原理是在参数上加0.5然后进行下取整。
6. switch 是否能作用在byte 上,是否能作用在long 上,是否能作用在String上?
expr可以是byte、short、char、int、enum、String类型,但是long类型不能
7. << 左移运算符相当于2的乘方
2 << 3(左移3位相当于乘以2的3次方,右移3位相当于除以2的3次方)
运算速度比 2*8 快
8. Java 中会存在内存泄漏吗,请简单描述
理论上Java因为有垃圾回收机制(GC)不会存在内存泄露问题(这也是Java被广泛使用于服务器端编程的一个重要原因);然而在实际开发中,可能会存在无用但可达的对象,这些对象不能被GC回收,因此也会导致内存泄露的发生。例如hibernate的Session(一级缓存)中的对象属于持久态,垃圾回收器是不会回收这些对象的,然而这些对象中可能存在无用的垃圾对象,如果不及时关闭(close)或清空(flush)一级缓存就可能导致内存泄露
9. 怎样将GB2312编码的字符串转换为ISO-8859-1编码的字符串
String s1 = "你好";
String s2 = new String(s1.getBytes("GB2312"), "ISO-8859-1");
10. try{}里有一个return语句,那么紧跟在这个try后的finally{}里的代码会不会被执行,什么时候被执行,在return前还是后
会执行,在return前执行。
在finally中改变返回值的做法是不好的,因为如果存在finally代码块,try中的return语句不会立马返回调用者,而是记录下返回值,待finally代码块执行完毕之后再向调用者返回其值,然后如果在finally中修改了返回值,就会返回修改后的值
11. List、Set、Map是否继承自Collection接口
List、Set 是,Map 不是。Map是键值对映射容器,与List和Set有明显的区别,而Set存储的零散的元素且不允许有重复元素(数学中的集合也是如此),List是线性结构的容器,适用于按数值索引访问元素的情形。
12. Thread类的sleep()方法和对象的wait()方法都可以让线程暂停执行,它们有什么区别
sleep()方法(休眠)是线程类(Thread)的静态方法,调用此方法会让当前线程暂停执行指定的时间,将执行机会(CPU)让给其他线程,但是对象的锁依然保持,因此休眠时间结束后会自动恢复。wait()是Object类的方法,调用对象的wait()方法导致当前线程放弃对象的锁(线程暂停执行),进入对象的等待池(wait pool),只有调用对象的notify()方法(或notifyAll()方法)时才能唤醒等待池中的线程进入等锁池(lock pool),如果线程重新获得对象的锁就可以进入就绪状态
13.启动一个线程
Runnable runnable = new runnable(){
public void run(){
// 执行的内容
}
}
Thread t = new Thread(runnbale);
t.start();
14. 事务的ACID是指什么
- 原子性(Atomic):事务中各项操作,要么全做要么全不做,任何一项操作的失败都会导致整个事务的失败;
- 一致性(Consistent):事务结束后系统状态是一致的;
- 隔离性(Isolated):并发执行的事务彼此无法看到对方的中间状态;
- 持久性(Durable):事务完成后所做的改动都会被持久化,即使发生灾难性的失败。通过日志和同步备份可以在故障发生后重建数据
15. 获得一个类的类对象有哪些方式
- 方法1:类型.class,例如:String.class
- 方法2:对象.getClass(),例如:”hello”.getClass()
- 方法3:Class.forName(),例如:Class.forName(“java.lang.String”)
16. 几个常用的设计模式
- 工厂模式:工厂类可以根据条件生成不同的子类实例,这些子类有一个公共的抽象父类并且实现了相同的方法,但是这些方法针对不同的数据进行了不同的操作(多态方法)。当得到子类的实例后,开发人员可以调用基类中的方法而不必考虑到底返回的是哪一个子类的实例。
- 代理模式:给一个对象提供一个代理对象,并由代理对象控制原对象的引用。
- 适配器模式:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起使用的类能够一起工作。
- 单例模式:一个类只有一个实例,即一个类只有一个对象实例
17. 冒泡排序
for(int i=0;i<arr.length-1;i++){//外层循环控制排序趟数
for(int j=0;j<arr.length-1-i;j++){
if(arr[j]>arr[j+1]){
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
18. 线程有哪些状态
等待执行
执行中
睡眠
阻塞
等待
死亡
19. 什么是死锁
当线程 A 持有独占锁a,并尝试去获取独占锁 b 的同时,线程 B 持有独占锁 b,并尝试获取独占锁 a 的情况下,就会发生 AB 两个线程由于互相持有对方需要的锁,而发生的阻塞现象,我们称为死锁
20.MySQL 常用的引擎
- InnoDB 引擎:mysql 5.1 后默认的数据库引擎,提供了对数据库 acid 事务的支持,并且还提供了行级锁和外键的约束,它的设计的目标就是处理大数据容量的数据库系统。MySQL 运行的时候,InnoDB 会在内存中建立缓冲池,用于缓冲数据和索引。但是该引擎是不支持全文搜索,同时启动也比较的慢,它是不会保存表的行数的,所以当进行 select count(*) from table 指令的时候,需要进行扫描全表。由于锁的粒度小,写操作是不会锁定全表的,所以在并发度较高的场景下使用会提升效率的。
- MyIASM 引擎:不提供事务的支持,也不支持行级锁和外键。因此当执行插入和更新语句时,即执行写操作的时候需要锁定这个表,所以会导致效率会降低。不过和 InnoDB 不同的是,MyIASM 引擎是保存了表的行数,于是当进行 select count(*) from table 语句时,可以直接的读取已经保存的值而不需要进行扫描全表。所以,如果表的读操作远远多于写操作时,并且不需要事务的支持的,可以将 MyIASM 作为数据库引擎的首选。
21.乐观锁和悲观锁
- 乐观锁:每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。
- 悲观锁:每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻止,直到这个锁被释放。
22.Redis 为什么是单线程的
因为 cpu 不是 Redis 的瓶颈,Redis 的瓶颈最有可能是机器内存或者网络带宽。既然单线程容易实现,而且 cpu 又不会成为瓶颈,那就顺理成章地采用单线程的方案了。
关于 Redis 的性能,官方网站也有,普通笔记本轻松处理每秒几十万的请求。
而且单线程并不代表就慢 nginx 和 nodejs 也都是高性能单线程的代表。
23.Redis 支持的数据类型有哪些
Redis 支持的数据类型:string(字符串)、list(列表)、hash(字典)、set(集合)、zset(有序集合)
24.JVM 运行时数据区
- 程序计数器(Program Counter Register):当前线程所执行的字节码的行号指示器,字节码解析器的工作是通过改变这个计数器的值,来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能,都需要依赖这个计数器来完成;
- Java 虚拟机栈(Java Virtual Machine Stacks):用于存储局部变量表、操作数栈、动态链接、方法出口等信息;
- 本地方法栈(Native Method Stack):与虚拟机栈的作用是一样的,只不过虚拟机栈是服务 Java 方法的,而本地方法栈是为虚拟机调用 Native 方法服务的;
- Java 堆(Java Heap):Java 虚拟机中内存最大的一块,是被所有线程共享的,几乎所有的对象实例都在这里分配内存;
- 方法区(Methed Area):用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。
25.堆栈的区别
- 功能方面:堆是用来存放对象的,栈是用来执行程序的。
- 共享性:堆是线程共享的,栈是线程私有的。
- 空间大小:堆大小远远大于栈。
26.数据结构
- 数组
- 链表(单项、双向)
- 栈
- 队列
- 树()
- 图
27.spring的ioc和aop
IOC容器:就是具有依赖注入功能的容器,是可以创建对象的容器,IOC容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。通常new一个实例,控制权由程序员控制,而"控制反转"是指new实例工作不由程序员来做而是交给Spring容器来做。。在Spring中BeanFactory是IOC容器的实际代表者。
AOP就是纵向的编程,如业务1和业务2都需要一个共同的操作,与其往每个业务中都添加同样的代码,不如写一遍代码,让两个业务共同使用这段代码。在日常有订单管理、商品管理、资金管理、库存管理等业务,都会需要到类似日志记录、事务控制、权限控制、性能统计、异常处理及事务处理等。AOP把所有共有代码全部抽取出来,放置到某个地方集中管理,然后在具体运行时,再由容器动态织入这些共有代码。
28.B树、B-树、B+树
B树:
- 又叫二叉搜索树
- 所有非叶子结点至多拥有两个儿子(Left和Right)
- 所有结点存储一个关键字
- 非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树
B-树:
- 是一种多路搜索树(并不是二叉的)
- 定义任意非叶子结点最多只有M个儿子;且M>2;
- 根结点的儿子数为[2, M];
- 除根结点以外的非叶子结点的儿子数为[M/2, M];
- 每个结点存放至少M/2-1(取上整)和至多M-1个关键字;(至少2个关键字)
- 非叶子结点的关键字个数=指向儿子的指针个数-1;
- 非叶子结点的关键字:K[1], K[2], …, K[M-1];且K[i] < K[i+1];
- 非叶子结点的指针:P[1], P[2], …, P[M];其中P[1]指向关键字小于K[1]的
子树,P[M]指向关键字大于K[M-1]的子树,其它P[i]指向关键字属于(K[i-1], K[i])的子树;
- 所有叶子结点位于同一层
如:(M=3)
B-树的搜索,从根结点开始,对结点内的关键字(有序)序列进行二分查找,如果命中则结束,否则进入查询关键字所属范围的儿子结点;重复,直到所对应的儿子指针为空,或已经是叶子结点。
B-树的特性:
1.关键字集合分布在整颗树中;
2.任何一个关键字出现且只出现在一个结点中;
3.搜索有可能在非叶子结点结束;
4.其搜索性能等价于在关键字全集内做一次二分查找;
5.自动层次控制
B+树:
-
- 其定义基本与B-树同,除了:
- 非叶子结点的子树指针与关键字个数相同;
- 非叶子结点的子树指针P[i],指向关键字值属于[K[i], K[i+1])的子树
(B-树是开区间);
-
- 为所有叶子结点增加一个链指针;
- 所有关键字都在叶子结点出现;
如:(M=3)
B+的搜索与B-树也基本相同,区别是B+树只有达到叶子结点才命中(B-树可以在
非叶子结点命中),其性能也等价于在关键字全集做一次二分查找;
B+的特性:
1.所有关键字都出现在叶子结点的链表中(稠密索引),且链表中的关键字恰好是有序的;
2.不可能在非叶子结点命中;
3.非叶子结点相当于是叶子结点的索引(稀疏索引),叶子结点相当于是存储(关键字)数据的数据层;
4.更适合文件索引系统;
小结
B树:二叉树,每个结点只存储一个关键字,等于则命中,小于走左结点,大于走右结点;
B-树:多路搜索树,每个结点存储M/2到M个关键字,非叶子结点存储指向关键字范围的子结点;
所有关键字在整颗树中出现,且只出现一次,非叶子结点可以命中;
B+树:在B-树基础上,为叶子结点增加链表指针,所有关键字都在叶子结点中出现,非叶子结点作为叶子结点的索引;B+树总是到叶子结点才命中;
29. 满二叉树
除最后一层(叶子节点)无任何子节点外,每一层上的所有结点都有两个子结点的二叉树
高度为h,并且由2h-1个结点组成的二叉树,称为满二叉树
30.完全二叉树
若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树
(1)所有的叶结点都出现在第k层或k-l层(层次最大的两层)
(2)对任一结点,如果其右子树的最大层次为L,则其左子树的最大层次为L或L+l。
一棵二叉树至多只有最下面的两层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,则此二叉树成为完全二叉树,并且最下层上的结点都集中在该层最左边的若干位置上,而在最后一层上,右边的若干结点缺失的二叉树,则此二叉树成为完全二叉树。
31. String不可变是因为在JDK中String类被声明为一个final类
32.Vector,ArrayList, LinkedList的区别是什么
- Vector、ArrayList都是以类似数组的形式存储在内存中,LinkedList则以链表的形式进行存储。
- List中的元素有序、允许有重复的元素,Set中的元素无序、不允许有重复元素。
- Vector线程同步,ArrayList、LinkedList线程不同步。
- LinkedList适合指定位置插入、删除操作,不适合查找;ArrayList、Vector适合查找,不适合指定位置的插入、删除操作。
- ArrayList在元素填满容器时会自动扩充容器大小的50%,而Vector则是100%,因此ArrayList更节省空间
33.Tomcat,Apache,JBoss的区别
Apache/nginx是Http服务器,Tomcat是web应用(java)服务器,JBoss是应用服务器
https://www.iteye.com/blog/foohsinglong-1195780
weblogic是用于开发、集成、部署和管理大型分布式web应用、网络应用和数据库应用的java应用服务器,将java的动态功能和java enterprise标准的安全性引入大型网络应用的开发集成部署和管理之中。
Tomcat和weblogic最大的区别是:weblogic是将j2ee的应用服务器(web container+EJB container),包括ejb、jsp、servlet、jms等,属于全能型的。
tomcat只能算是web container,是官方指定的jsp&servlet容器,只实现了jsp/servlet的相关规范,不支持EJB。
34.Session, Cookie区别
- Session由应用服务器维护的一个服务器端的存储空间;Cookie是客户端的存储空间,由浏览器维护。
- 用户可以通过浏览器设置决定是否保存Cookie,而不能决定是否保存Session,因为Session是由服务器端维护的。
- Session中保存的是对象,Cookie中保存的是字符串。
- Session和Cookie不能跨窗口使用,每打开一个浏览器系统会赋予一个SessionID,此时的SessionID不同,若要完成跨浏览器访问数据,可以使用 Application。
- Session、Cookie都有失效时间,过期后会自动删除,减少系统开销。
35. Servlet的生命周期
- nit():负责初始化Servlet对象。
- service():负责响应客户端请求。
- destroy():当Servlet对象推出时,负责释放占用资源。
36. hibernate的一级缓存和二级缓存
Configuration —— SessionFactory —— Session
一级缓存:
是Session级别的缓存,一个Session做了一个查询操作,它会把这个操作的结果放在一级缓存中,如果短时间内这个session(一定要同一个session)又做了同一个操作,那么hibernate直接从一级缓存中拿,而不会再去连数据库中取数据。只能有限的提高一点点系统性能,最重要的功能:提供给了一个临时存放持久化对象的空间。
二级缓存:
是SessionFactory级别的缓存,顾名思义,就是查询的时候会把查询结果缓存到二级缓存中,如果同一个sessionFactory创建的某个session执行了相同的操作,hibernate就会从二级缓存中拿结果,而不会再去连接数据库。所有的get,load方法,总是先查一级缓存,再查二级缓存,如果都没有,再去数据库里面查询,
37. 反射
反射机制的定义:
是在运行状态中,对于任意的一个类,都能够知道这个类的所有属性和方法,对任意一个对象都能够动态地通过反射机制调用一类的任意方法,这种动态获取类信息及动态调用类对象方法的功能称为java的反射机制
反射的作用:
- 动态地创建类的实例,将类绑定到现有的对象中,或从现有的对象中获取类型。
- 应用程序需要在运行时从某个特定的程序集中载入一个特定的类
38. hibernate和mybatis的区别
一、两者最大的区别
针对简单逻辑,Hibernate与MyBatis都有相应的代码生成工具,可以生成简单基本的DAO层方法。
针对高级查询,MyBatis需要手动编写SQL语句,以及ResultMap,而Hibernate有良好的映射机制,开发者无需关心SQL的生成与结果映射,可以更专注于流程。
二、开发难度对比
Hibernate的开发难度大于MyBatis,主要由于Hibernate比较复杂,庞大,学习周期比较长。
MyBatis则相对简单,并且MyBatis主要依赖sql的书写,让开发者更熟悉sql。
三、sql书写比较
Hibernate也可以自己写sql来指定需要查询的字段,但这样就破坏了Hibernate开发的简洁性,不过Hibernate具有自己的日志统计。
MyBatis的sql是手动编写的,所以可以按照要求指定查询的字段,不过没有自己的日志统计,所以要借助Log4j来记录日志。
四、数据库扩展性计较
Hibernate与数据库具体的关联在XML中,所以HQL对具体是用什么数据库并不是很关心
MyBatis由于所有sql都是依赖数据库书写的,所以扩展性、迁移性比较差。
五、缓存机制比较
Hibernate的二级缓存配置在SessionFactory生成配置文件中进行详细配置,然后再在具体的表对象映射中配置那种缓存。
MyBatis的二级缓存配置都是在每个具体的表对象映射中进行详细配置,这样针对不同的表可以自定义不同的缓冲机制,并且MyBatis可以在命名空间中共享相同的缓存配置和实例,通过Cache-ref来实现。
六、sql查询性能
复杂sql,MyBatis可以自己优化sql语句,起到优化查询速度的效果
39.维持数据库的一致性
依次可以用外键、CHECK约束、规则约束、触发器、客户端程序,一般认为,离数据越近的方法效率越高。
外键是最高效的一致性维护方法
40.使用通过top分页
如何查200到300行的记录,可以通过top关键字:
select top 100 * from tableName where id not in (select top 200 id from tableName);
查询n到m行记录的通用公式:
select top (m-n) * from tableName where id not in (select top n * from tableName)
41. Union和Union All到底有什么区别
- Union:对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序;
- Union All:对两个结果集进行并集操作,包括重复行,不进行排序;
42.sql优化
- Sql查询语句尽量用上索引,尽量避免全表扫描
- 避免在 where 子句中对字段进行 is null 或者 is not null 判断,否则将导致引擎放弃使用索引而进行全表扫描。用 not null + default默认值的方式替换。
select id from t where num is null
可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:
select id from t where num=0
- 避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描
- 全模糊查询lilke‘%...%’会导致使用全扫描,首先尽量避免模糊查询,如果因为业务需要一定要使用模糊查询,则至少保证不要使用全模糊查询,对于右模糊查询,即like ‘…%’,是可以使用索引的;左模糊like‘%...’无法直接使用索引,但可以利用reverse反转右模糊变成左迷糊。全模糊是无法优化的,一定要的话考虑用搜索引擎
reverse反转:
select * from student where name like '%三';
可以改成:
select * from student where reverse(name) like reverse('%三');
- in的相关子查询用EXISTS代替
select PUB_NAME from PUBLISHERS where PUB_ID in(select PUB_ID FROM TITLES where TYPE = ’BUSINESS’)
可以改成:
select PUB_NAME from PUBLISHERS where EXISTS (select * FROM TITLES where TYPE = ’BUSINESS’ and PUB_ID= PUBLISHERS.PUB_ID)
- 尽量避免在 WHERE 子句中使用 OR 来连接条件,可以用UNION ALL来替换
SELECT ID FROM T WHERE NUM=10 OR NUM=20
可以这样查询:
SELECT ID FROM T WHERE NUM=10
UNION ALL
SELECT ID FROM T WHERE NUM=20”
- or语句使用不当会引起全表扫描
原因:where子句中比较的两个条件,一个有索引,一个没索引,使用or则会引起全表扫描。例如:where A=:1 or B=:2,A上有索引,B上没索引,则比较B=:2时会重新开始全表扫描。
- in(1,2,3)可以用 between and
SELECT ID FROM T WHERE NUM IN(1,2,3);
可以改成:
SELECT ID FROM T WHERE NUM BETWEEN 1 AND 3;
- 应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。
select id from t where substring(name,1,3)='abc' -- name以abc开头的id
应改为:
select id from t where name like 'abc%'
- 避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描
select id from t where num/2=100
应改为:
select id from t where num=100*2
- 字段的设计
- 数据类型尽量用数字型,数字型的比较比字符型的快很多;
- 数据类型尽量小,这里的尽量小是指在满足可以预见的未来需求的前提下的;
- 尽量不要允许NULL,除非必要,可以用NOT NULL+DEFAULT代替;
- 少用TEXT和IMAGE,二进制字段的读写是比较慢的,而且,读取的方法也不多,大部分情况下最好不用;
- 自增字段要慎用,不利于数据迁移;
- 索引的设计
- 根据数据量决定哪些表需要增加索引,数据量小的可以只有主键
- 根据使用频率决定哪些字段需要建立索引,选择经常作为连接条件、筛选条件、聚合查询、排序的字段作为索引的候选字段
- 把经常一起出现的字段组合在一起,组成组合索引,组合索引的字段顺序与主键一样,也需要把最常用的字段放在前面,把重复率低的字段放在前面
- 一个表不要加太多索引,因为索引影响插入和更新的速度
- 索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率, 因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。 一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要
- 不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段,在实际部署后数据在带宽中传输会造成大量的性能损耗
- 尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写
43.通过explain命令来查看SQL语句的执行计划
Explain sql语句
- id: SELECT识别符。这是SELECT的查询***,id如果相同,可以认为是一组,从上往下顺序执行;在所有组中,id值越大,优先级越高,越先执行。
- select_type:表示查询的类型。
- SIMPLE(简单SELECT,不使用UNION或子查询等)
- PRIMARY(子查询中最外层查询,查询中若包含任何复杂的子部分,最外层的select被标记为PRIMARY)
- UNION(UNION中的第二个或后面的SELECT语句)
- DEPENDENT UNION(UNION中的第二个或后面的SELECT语句,取决于外面的查询)
- UNION RESULT(UNION的结果,union语句中第二个select开始后面所有select)
- SUBQUERY(子查询中的第一个SELECT,结果不依赖于外部查询)
- DEPENDENT SUBQUERY(子查询中的第一个SELECT,依赖于外部查询)
- DERIVED(派生表的SELECT, FROM子句的子查询)
- UNCACHEABLE SUBQUERY(一个子查询的结果不能被缓存,必须重新评估外链接的第一行)
- table:输出结果集的表。显示这一步所访问数据库中表名称(显示这一行的数据是关于哪张表的),有时不是真实的表名字,可能是简称,例如的e,d,也可能是第几步执行的结果的简称
- partitions:匹配的分区
- type:表示表的连接类型。对表访问方式,表示MySQL在表中找到所需行的方式,又称“访问类型”。 (从上到下,性能从差到好)
- ALL:Full Table Scan, MySQL将遍历全表以找到匹配的行
- index: Full Index Scan,index与ALL区别为index类型只遍历索引树
- range:只检索给定范围的行,使用一个索引来选择行
- ref: 表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
- eq_ref: 类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件
- const、system: 当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量,system是const类型的特例,当查询的表只有一行的情况下,使用system
- NULL: MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。
- possible_keys:表示查询时,可能使用的索引。显示可能应用在这张表中的索引,一个或多个。查询涉及到的字段上若存在索引,则该索引奖杯列出,但不一定被查询实际使用。
- key:表示实际使用的索引,必然包含在possible_keys中,要想强制MySQL使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。
- key_len:索引字段的长度。表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度(key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的)不损失精确性的情况下,长度越短越好
- ref:列与索引的比较。ref显示索引的哪一列被使用了,如果可能的话,是一个常数,哪些列或者常量被用于查找索引列上的值。 只有当type为ref的时候,ref这列才会有值
- rows:扫描出的行数(估算的行数)
- filtered:按表条件过滤的行百分比
- Extra:执行情况的描述和说明,该列包含MySQL解决查询的详细信息
- Using index:索引覆盖。什么是索引覆盖呢?就是,查询的列都在索引里面可以找到,这样就不用去数据库里面查找了。性能全表扫描高。如果这里用到了where条件,那么条件必须是索引的前缀列(查找使用了索引,查询结果覆盖了索引)
- Using index condition:查找使用了索引,但是需要回表查询数据
- Using where:不用读取表中所有信息,仅通过索引就可以获取所需数据,这发生在对表的全部的请求列都是同一个索引的部分的时候,表示mysql服务器将在存储引擎检索行后再进行过滤
- Using temporary:表示MySQL需要使用临时表来存储结果集,常见于排序和分组查询,常见 group by ; order by
- Using filesort:当Query中包含 order by 操作,而且无法利用索引完成的排序操作称为“文件排序”
- Using join buffer:该值强调了在获取连接条件时没有使用索引,并且需要连接缓冲区来存储中间结果。如果出现了这个值,那应该注意,根据查询的具体情况可能需要添加索引来改进能
- Impossible where:这个值强调了where语句会导致没有符合条件的行(通过收集统计信息不可能存在结果)
- Select tables optimized away:这个值意味着仅通过使用索引,优化器可能仅从聚合函数结果中返回一行
- No tables used:Query语句中使用from dual 或不含任何from子句