4399面经
sql调优
创建索引
-
尽量避免全表扫描,考虑在where及order by涉及的列上建立索引
-
在经常需要进行检索的字段上创建索引
- 一个表的索引数最好不要超过6个,若太多应考虑不常使用的索引是否有必要。索引不是越多越好,虽然提高查询效率,但降低了insert和update的效率,insert和update可能会重建索引。且InnoDB的索引会占据表空间,减少表数据的存储。
避免在索引上使用计算
在where字句中,如果索引列是计算或者函数的一部分,将不会使用索引而使用全表查询,同时在in和exists中通常使用exists,因为in不走索引
/*效率低*/
select * from user salary*22>11000
/*效率低*/
select * from user salary>11000/22
使用预编译查询
程序中通常是根据用户的输入来动态执行sql,这是应该尽量使用参数化sql,这样不仅可以避免sql注入漏洞攻击,最重要数据库会对这些参数化sql进行预编译,这样第一次执行的时候DBMS会为这个sql进行查询优化并且执行预编译,这样以后再执行这个sql的时候就直接使用预编译的结果,这样可以大大提高执行的速度
调整Where字句中的连接顺序
DBMS一般采用自下而上的顺序解析where字句,根据这个原理表连接最好写在其他where条件之前,那些可以过滤掉最大数量记录----排除越多的条件放在第一个
在用MySQL查询数据库的时候,连接了很多个过滤条件,发现非常慢。例如:SELECT … WHERE p.languages_id=1 AND t.type=1 AND p.products_id IN (472,474),这样查询需要20多秒,虽然在各个字段上都建立了索引。用分析Explain SQL一分析,发现在第一次分析过程中就返回了几万条数据:WHERE p.languages_id=1 ,然后再依次根据条件缩小范围。
然后稍微改变一下WHERE字段的位置之后,速度就有了明显地提高:WHERE p.products_id IN (472,474) AND p.languages_id=1 AND t.type=1,这样第一次的过滤条件是p.products_id IN (472,474),它返回的结果只有不到10条,接下来还要根据其它的条件来过滤,自然在速度上有了较大的提升。经过实践发现,不要以为WHERE中的字段顺序无所谓,可以随便放在哪,应该尽可能地第一次就过滤掉大部分无用的数据,只返回最小范围的数据。
尽量将多条sql语句压缩到一句sql中
每次执行sql的时候都要建立网络连接,进行权限校验,进行sql语句的查询,发送执行结果,这个过程非常耗时,因此应该尽量避免过多的执行sql语句,能够压缩到一句sql执行的语句就不要用多条来执行
用where字句替换having字句
避免使用having字句,因为having只会在检索出所有结果之后才对结果进行过滤,而 where则是在聚合前筛选记录,如果能通过where字句限制记录的数目,那就能减少这方面的开销。HAVING中的条件一般用于聚合函数 的过滤,除此之外,应该将条件写在where字句中。
使用表的别名
当在SQL语句中连接多个表时,请使用表的别名并把别名前缀于每个列名上。这样就可以减少解析的时间并减少哪些有列名歧义引起的语法错误。
用union all替换union
当SQL语句需要union两个查询结果集合时,即使检索结果中不会有重复的记录,如果使用union这两个结果集 同样会尝试进行合并,然后在输出最终结果前进行排序,因此如果可以判断检索结果中不会有重复的记录时候,应该用union all,这样效率就会因此得到提高。
查询select语句优化
- 尽量不使用*号查询,用具体的字段代替,不要返回用不到的字段
- 避免在where字句中对字段进行null值判断,否则引擎放弃使用索引而进行全表查询
索引失效
- like以%开头,索引无效,当like前缀没有%,后缀有%,索引有效
- or语句前后没有同时使用索引。当or左右查询只有一个是索引,该索引失效。
- 组合索引,不是使用第一索引,索引失效
- 数据类型出现隐式转化。如varchar不加单引号的话可能自动转换为int型,使索引无效,产生全表扫描
select * from emp where job="123";
select * from emp where job=123; --索引失效
5.在索引列上使用IS NULL或IS NOT NULL操作。索引是不索引空值的
select * from emp where ename is not null;
6.在索引字段上使用not,<>,!=是用不到索引的,对他的处理只会产生全表扫描
7.对索引字段进行计算操作、使用函数
8.全表扫描速度比索引速度快时,mysql会使用全表扫描,索引失效
session与cookie的关系
session是依赖cookie实现的,服务器默认为浏览器在cookie中设置sessionid,浏览器在向服务器请求过程中传输cookie包含sessionid,服务器根据sessionid获取出会话存储的信息
-
数据存储
cookie以明文的方式存储在浏览器端,session存储在服务器端
-
安全性
由于存储位置的原因,也就出现了浏览器端是不安全的,服务端更为安全
-
生命周期
cookie的生命周期是可以累计时间,即到点就失效;Session是以最后 一次访问时间为倒计时的开始时间,同时,它还可以直接调用api来使它失效
-
使用原则
cookie的缺陷,每个站点只能保存20个cookie,每个cookie大小4k以内,session是存放服务器端,会占用服务器内存,因此不要往session中存放过多过大的对象
Java锁
-
乐观锁/悲观锁
- 乐观锁:每次拿数据时都认为别人不会修改,所以不会上锁,但在更新的时候会判断在此期间别人有没有去更新这个数据,可以使用版本号等机制。适合多读的应用类型,这样可以提高吞吐量。
- 悲观锁: 总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,每次拿数据的时候都会上锁,别人想拿到这个数据就会阻塞直到它拿到锁
悲观锁适合写操作非常多的场景,乐观锁适合读操作非常多。
悲观锁在Java中的使用,就是利用各种锁
乐观锁在Java中的使用,是无锁编程,常常使用的是CAS算法
-
独享锁/共享锁
独享锁是指该锁一次只能被一个线程所持有
共享锁是指该锁可以被多个线程持有
对于ReentrantLock而言,是独享锁。但是对于ReadWriteLock,其读锁是共享锁,其写锁是独享锁
-
互斥锁/读写锁
独享锁和共享锁是广义的说法,互斥锁/读写锁就是具体的实现
互斥锁在Java中的具体实现就是ReentrantLock
读写锁在Java中的具体实现就是ReadWriteLock
-
可重入锁
可重入锁又名递归锁,是指在同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁。
-
公平锁和非公平锁
公平锁指多个线程按照申请锁的顺序来获得锁
非公平锁指多个线程获取锁的顺序不是按申请锁的顺序,由CPU调度
-
分段锁
分段锁其实是一种锁的设计,并不是具体的一种锁,对于ConcurrentHashMap而言,其并发的实现就是通过分段锁的形式来实现高效的并发操作。
我们以ConcurrentHashMap来说一下分段锁的含义以及设计思想,ConcurrentHashMap中的分段锁称为Segment,它即类似于HashMap(JDK7和JDK8中HashMap的实现)的结构,即内部拥有一个Entry数组,数组中的每个元素又是一个链表;同时又是一个ReentrantLock(Segment继承了ReentrantLock)。
当需要put元素的时候,并不是对整个hashmap进行加锁,而是先通过hashcode来知道他要放在哪一个分段中,然后对这个分段进行加锁,所以当多线程put的时候,只要不是放在一个分段中,就实现了真正的并行的插入。
但是,在统计size的时候,可就是获取hashmap全局信息的时候,就需要获取所有的分段锁才能统计。
分段锁的设计目的是细化锁的粒度,当操作不需要更新整个数组的时候,就仅仅针对数组中的一项进行加锁操作。
-
偏向锁/轻量级锁/重量级锁
偏向锁是指一段同步代码一直被一个线程所访问,那么该线程会自动获取锁。降低获取锁的代价。
轻量级锁是指当锁是偏向锁的时候,被另一个线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,提高性能。
重量级锁是指当锁为轻量级锁的时候,另一个线程虽然是自旋,但自旋不会一直持续下去,当自旋一定次数的时候,还没有获取到锁,就会进入阻塞,该锁膨胀为重量级锁。重量级锁会让他申请的线程进入阻塞,性能降低。
-
自旋锁
在Java中,自旋锁是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环会消耗CPU。
OSI七层模型
–开放式系统互联
- 物理层
- 数据链路层
- 网络层
- IP协议
- 传输层
- TCP协议
- 会话层
- 表示层
- 应用层
- HTTP协议
TCP/IP五层模型
- 物理层
- 数据链路层
- 网络层
- 传输层
- 应用层
- 会话层
- 表示层
- 应用层
http协议的端口
常用端口号:80/8080/8081/3128/9098
创建线程池的方法
线程池七大参数:最大线程池大小,最大核心线程大小,超时等待时间,超时时间单位,阻塞队列,线程工程,拒绝策略
如何保证线程安全
-
互斥同步
- ReentrantLock
- synchronized
-
非阻塞同步
- CAS:未获得资源,循环等待不阻塞
-
无须同步方案
- 线程不涉及共享资源
MyISAM与InnoDB的区别
-
存储结构
- MyISAM每个表都分为三个文件:表格定义,数据文件,索引文件
- InnoDB所有表都保存在一个数据文件中,InnoDB表大小只受限于操作系统文件的大小,一般为2GB
-
存储空间
- MyISAM可被压缩,存储空间较小
- InnoDB的表需要更多的内存和存储,它会在主内存中建立专用的缓冲池用于高速缓存数据和索引
-
记录存储顺序
- MyISAM按插入顺序保存
- InnoDB按主键大小有序插入
-
外键
- MyISAM不支持
- InnoDB支持
-
事务
- MyISAM不支持
- InnoDB支持
-
锁支持
- MyISAM只有表锁
- InnoDB有行锁和表锁,默认行锁,行锁在查询字段带有索引的时候才会触发,不然还是使用表锁
-
select count(*)
MyISAM更快,内部维护了一个计数器可以直接调用
-
索引
- 都是B+树索引
-
哈希索引
- MyISAM不支持
- InnoDB支持
-
全文索引
- MyISAM支持
- InnoDB不支持