不同HTTP协议的不同TCP连接模式:
HTTP/1.0:TCP连接在http请求创建时同步创建,http请求发送到服务器端,服务器端响应后TCP连接即关闭。
HTTP/1.1:以某种方式连接继续保持,一个请求传输完成后另一个请求接着传输。好处:多请求下不必多次进行“三次握手”进行连接,防止了不必要的资源消耗。
HTTP/2:对HTTP/1.1进行升级,同一个TCP连接支持并发传输http请求。
三次握手详解:
三次握手就是TCP连接的建立,必须是一方主动打开,另一方被动打开。三次握手之前主动打开连接的客户端A结束CLOSED阶段,被动打开连接的服务端B也结束CLOSED阶段,并进入LISEN监听阶段,随后进行三次握手。
过程:
1.客户端向服务端发送一条TCP报文,告知服务器端请求建立新连接
2.服务端接受到客户端的报文后,结束LISEN阶段,并返回一段TCP报文告知客户端已接受到来自客户端的数据,同意建立新连接。
3.客户端接收到来自服务端的TCP报文后,明确了从客户端到服务端的数据传输是正常的,向服务端返回最后一段TCP报文,告知服务端已接收到服务端的数据。
之后进行正常的数据传输。
第一次:
SYN:标志位,表示发起一个新连接
seq:序号,占32位,用来标识从TCP源向目的端发送的字节流,发送方发送数据时对此进行标记。
标记位为 SYN = 1,表示请求建立新连接
序号为 seq = x,x 一般为1
第二次:
ACK:标志位,表示确认序号有效
ack:确认号(非标志位的ACK),占32位,只有ACK标志位为1时,确认号字段才有效,ack = seq + 1
标志位:SYN = 1, ACK = 1,表示确认客户端发送的seq有效,服务器可正常接收客户端发送的数据,同意创建新连接
序号: seq = y,
确认号:ack = x + 1,表示收到客户端的序号seq = x,并将该值 + 1作为自己的确认号ack的值
第三次:
标志位:ACK = 1:表示确认收到服务器端同意连接的信号
序号:seq = x + 1:表示收到服务端的确认号ack,并+ 1作为自己的序号值
确认号:ack = y + 1:表示收到服务器端的序号seq,并+1作为自己的确认号ack的值
总结:
整个三次握手过程就像是你这个钢铁直男在追你的女神一样,你对你的女神说:我喜欢你我要追你;你女神回答你说:行,我知道你要追我了,你追吧;然后你收到了你女神的消息,自以为郑重其事的对你女神说:好,我知道你知道我要追你了。那我追你了。此时,你追你女神的事就定下来了,下边就开始追女神了,至于是送花还是吃饭就看你自己的了。
进行三次握手的原因:
①防止服务器端开启一些无用的连接增加不必要的开销
②防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
和三次握手建立连接一样,四次挥手也要求必须是一方主动释放,另一方被动释放
过程:
1、客户端想要释放连接,向服务器端发送一段TCP报文
2、服务器端接收到从客户端发出的TCP报文后,确认客户端想要释放连接,返回一段TCP报文给客户端
3、服务器端自发出报文后,做好释放服务器端到客户端方向的连接准备,再次向客户端发送一段TCP报文,随后停止在服务器端到客户端的方向上的发送数据,但此时仍可以接收从客户端传输过来的数据。
4、客户端收到服务端发来的TCP报文,确认服务器端已做好释放连接准备,向服务器端发送一段报文。
在服务器端接收到最后客户端发来的TCP报文后,正式确认关闭服务器端到客户端的连接。
FIN:标志位,表示释放一个连接
第一次:
FIN = 1:释放一个连接
seq = u:序号为u
第二次:
ACK = 1:标志位:表示接收到客户端的释放连接请求
seq = v:序号为v
ack = u + 1:确认号为u + 1,表示收到客户端的序号u,并将其 + 1 作为自己的确认号ack的值
随后服务器端开始准备释放服务器端到客户端方向上的连接
第三次:
FIN = 1,ACK = 1:标志位,表示已确认释放连接请求并准备好释放连接
seq = w:序号为w
ack = u + 1:确认号为u + 1,表示收到客户端的序号u,并将其 + 1 作为自己的确认号ack的值
第四次:
ACK = 1:标志位,表示已收到服务器准备好释放连接的信号
seq = u + 1: 表示是在收到了服务器端报文的基础上,将其确认号ack值作为本段报文序号的值。
ack = w + 1: 表示是在收到了服务器端报文的基础上,将其序号seq值作为本段报文确认号的值。
总结:
整个过程还是那个你和你女神的故事一样。你发现女神不是那么好追,想要放弃了。于是你对你女神说:我不想追你了;你女神给你回消息说:行,我知道了,然后开始把你送的玫瑰收拾收拾准备丢在垃圾桶。然后你女神又给你发了条信息说:我知道你不追我了,我也准备好把你送的玫瑰丢了。你收到女神的消息后心神交猝,感到有些累,但还是忍不住给你女神发了条消息:我知道你要把我送你的玫瑰丢了,你丢吧。从此,世上又多了个伤心又孤独的人。
TCP | UDP | |
---|---|---|
是否连接 | 面向连接 | 无连接 |
是否可靠 | 可靠,使用流量控制和拥塞控制 | 不可靠 |
连接对象个数 | 一对一通信 | 支持一对一,一对多,多对一,多对多交互通信 |
传输方式 | 面向字节流 | 面向报文 |
首部开销 | 最小20字节,最大60字节 | 开销较小,仅8字节 |
使用场景 | 适用于要求靠传输的应用,如文件传输 | 使用与实施应用,如视频会议,直播等 |
传输速度 | 较慢 | 较快 |
参考: https://www.cnblogs.com/ppzhang/p/10506237.html
流量控制:
TCP每发送一个数据,都要进行一次应答。当上一个数据包收到了应答再发送下一个。类似于你和你的siri聊天,你说一句它说一句,它不回你你就得等,时不时网络拥堵还得等半天,最后总是你匆匆结尾宛若个渣男。这种模式想都不用想效率低下慢的要死,为了提高效率,于是引用了窗口的概念。窗口相当于一堵墙上的一扇窗,只要你的东西不超过窗户的大小,就可以从墙的这边把东西递到那边(又想起了那些年在学校门口取外卖的时光了)。有了窗口之后,就可以无需等待确认应答继续发送数据,而窗口的大小就是可以继续发送数据量的最大值。
窗口实际上是操作系统开辟的一块内存空间,发送方在等到确认应答返回前必须在缓冲区保留已发送的数据,如果按期收到确认应答,则可以清空缓存区的相应数据。
总的来说流量控制就是能让发送方愉悦的发送数据并且控制发送速率不太快,让接收方来得及接收(举个不恰当的栗子,某度网盘为用户接收数据考虑限制下载速度几K/s)
拥塞控制:
流量控制主要解决发送数据的效率问题,但是没有解决数据传输过程中出现的问题。
试想一下,所有的电子设备失灵,只能依靠千里马进行信息传输,你给你女神买了她最爱吃的丝滑的不行的德某芙牌巧克力,让人骑马送过去,途中需要经过一座桥。你的女神收到了巧克力并吃了一口告诉你真的无比的丝滑,香的一批。你收到了女神的信息,派人骑马问她真的有这么丝滑吗?但是好巧不巧,那座桥是个豆腐渣工程,桥塌了,包工头还带着她小姨子跑了,附近的村民暂时搭了个独木桥,人很多,送信的马被堵在这里了。你等啊等等啊等,女神还是没有给你回消息是不是真的这么丝滑这么香的一批,于是你又派了个人骑马送信问是不是真的丝滑。第二个送信的人也来到了这座独木桥,送信人1刚好碰见,双方打了个招呼,一起骂你舔狗舔到最后一无所有。就这样,桥前排队的马越来越多,送信的人已经凑够了好几桌麻将开始搓麻将了,而你还是没有收到你女神的回信,而你的女神遇到了那个包工头,和包工头还有包工头的小姨子一起过上了没羞没躁的生活,从此世上又多了一个无情的舔狗。
这就是拥塞控制的要解决的问题,出现网络拥堵后,出现数据包丢包,延时等问题,此时TCP在定时器期限内接收不到数据,就会触发超时重传,但是网络拥堵了,重传的数据依然堵在网络中,接收方仍然接收不到数据,自然也就不会发送应答,就会陷入恶性循环,导致网络越来越堵,加重网络负担。于是TCP发扬了牺牲小我保大我的精神,降低发送的数据量,于是就有了拥塞控制,目的就是避免发送方的数据填满整个网络。
七层模型分别为:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层
应用层:功能:文件传输,电子邮件,文件服务,虚拟终端;所用协议:HTTP,FTP等
表示层:功能:数据格式化,代码转换,数据加密;无协议
会话层:功能:解除或建立与别的接点的联系;无协议
传输层:功能:提供端对端接口;所用协议:TCP,UDP
网络层:功能:为数据包选择路由;所用协议:IP,ICMP,RIP等
数据链路层:功能:传输有地址的帧,错误检测;所用协议:SLIP,ARP,PPP等
物理层:功能:以二进制数据心事在物理媒体上传输数据;所有协议:ISO02110,IEEE802,IEEE802.2
ARP: ARP协议是地址解析协议(Address Resolution Protocol)是通过解析IP地址得到MAC地址的,是一个在网络协议包中极其重要的网络传输协议,它与网卡有着极其密切的关系,在TCP/IP分层结构中,把ARP划分为网络层
FTP: FTP文件传输协议(File Transfer Protocol),用于Internet上的控制文件的双向传输,是一个应用程序。工作在TCP/IP协议族的应用层,其传输层协议是TCP协议,目的在于提高文件传输的共享性和可靠性,是基于客户/服务器模式工作的。FTP会建立两个连接,将命令与数据分开传输,提高传输效率。FTP使用两个端口,分别为控制端口(命令端口)和数据端口。控制端口号一般为21,数据端口一般为20。控制socket用来传输命令,数据socket用来传输数据。每一个FTP命令发送后,FTP服务器就会返回一个字符串,其中包含一个响应码和一些说明信息,其中响应码主要用于判断命令是否被成功执行了。
参考资料:Mark Allen Weiss著 数据结构与算法分析Java语言描述第三版 冯舜玺 陈越译(建议大家买原版不要买译本,译本翻译生硬,过于抽象不好理解) 严蔚敏 李冬梅 吴伟民 著 数据结构(C语言版 第2版)
线性表:由n(n>=0)个数据特性相同的元素构成的有限序列称为线性表,当n为0时,为空表
特点(非空线性表):
①只有一个首节点和一个尾结点
②除首尾节点外,其他的每个数据元素均只有一个前驱和一个后继
线性表分为:顺序表和链表,其中链表又可细分为单链表、双向链表、循环链表、二叉链表、十字链表、邻接表、邻接多重表等。
顺序表:用一组地址连续的存储单元依次存储元素的线性表,是一种随机存取的数据结构,例如:数组。
特点:逻辑上相邻的数据元素其物理次序也相邻。
缺点:插入或删除操作时需移动大量元素,另外由于数组元素具有相对固定的静态特性,当表中的数据元素个数较多且变化较大时操作过程复杂,易导致空间浪费。
链表:用一组任意的存储单元存储线性表的数据元素,这组存储单元可连续可不连续。
单链表:每个节点除数据本身外还存储直接后继存储位置,分别称为数据域和指针域,指针域中存储的信息又称为指针或链,非顺序存取结构,获取元素需从头指针开始。
单链表的易混淆名词
首元结点:存储第一个数据元素的节点
头结点:在首元结点之前,其指针域指向首元结点,数据域可不存东西,也可存储于数据元素类型相同的其他附加信息,如链表长度。
头指针:指向链表中第一个节点的指针。若链表有头结点,则头指针指向的节点为头节点,若链表无头节点,则头指针指向的节点为首元结点。
循环链表:与单链表相似,将表中最后一个节点的指针域指向头节点,形成一个环,即为循环链表。因此可通过任意一个结点出发均可找到表中其他结点。
双向链表:单链表的衍生,主要解决单链表查询效率低的问题。结点中有两个指针域,一个指向直接后继,一个指向直接前驱,也可有循环表
栈:限定仅在表尾进行插入或删除操作的线性表。尾端成为栈顶,头端称为栈底。遵循**后进先出(LIFO)**原则
栈的分类
栈也分为顺序栈与链栈,结构和顺序表及链表的结构相同,毕竟栈也是一种特殊的线性表。
队列:与栈相反,是一种**先进先出(FIFO)**的线性表;允许插入的一端称为队尾,允许删除的一端称为队头。
队列分类:
队列也分为顺序结构(循环队列)和链结构(链队列)。
树:n(n >= 0)个有限结点的有限集,n=0时为空树。(脑子里别全装啤酒炸鸡,现在腾出点地方想象一棵树,倒着长的树)
特点(非空树):
①有且只有一个根结点。(一棵树只有一个树根,如图的A)
②除根结点外的其余结点可分为m(m>0)个互不相交的有限集T1~Tm,其中每个集合本身又是一棵树,称为根的子树。(一棵大树有多个枝丫,一个枝丫就是一个子树)
二叉树:与树的定义相似,但是只有两个互不相交的子集,如图的E、K、L
特点:①二叉树每个结点至多只有两棵子树(二叉树中不存在度大于2的结点)
②二叉树的子树有左右之分, 左子树与右子树不能随意颠倒
遍历二叉树是指按某条搜索路径巡访树中每个结点,使得每个结点均被访问一次,而且仅被访问一次。
二叉树的遍历根据访问根结点的顺序分类共有三种,分别是先序遍历、中序遍历、后序遍历
先序遍历:①访问根节点②遍历左子树③遍历右子树
中序遍历:①中序遍历左子树②访问根节点③中序遍历右子树
后序遍历:①后序遍历左子树②后序遍历右子树③访问根节点
还记得你和你女神的故事吗?当初你追你女神的时候,你和你女神就像是在一条大马路上进行爱情追逐马拉松,可是你的女神总是在你的前边,你走过了所有你女神走过的路,还是见不到她,那么,你的女神妹妹到底去哪了呢?是的,她跟着包工头和包工头的小姨子躲进了天津之眼,而你追到了天津之眼之后,总是在她后边,一直追啊追追啊追,你知道她一定在这里,你们就在上边转啊转转啊转,但就是追不到她,看起来你们就是在一个死循环中,谁都遇不到谁,从此,世间又多了一个相思成疾、孤独终老的单身狗…
在一个未知的单链表中,如果出现环,就会出现陷入循环链的一遍一遍无终止的进行遍历,这种尴尬的境地谁都不想遇见,谁不想抱着女神回家睡热炕头啊
于是,单链表环存在的判断就显得极其重要。在这里,我们不考虑空链的情况直接进行环存在的判断。
想一想大学四年每年都要经历的体测,那个800/1000米项目是不是爽的飞天。在起点的时候明明说好一起划水摸鱼溜达到终点,可总是有人背信弃义令人不齿超过你比你先到终点然后嘲讽你像只王八在那慢慢溜达。现在想一想,为什么那些先到终点的狗贼比你快。原因无他,肯定他速度快呗。现在我们把跑道无限加长,但仍然是个圈。只要他速度够快,哪怕速度比你快一点点,只要速度不变,不管天长地久还是海枯石烂,那个比你快的王八蛋是不是一定会甩你一圈再次遇见你然后嘲讽你这只小王八。
判断单链表是否有环也是这个道理。现在设两个指针,分别为指针p和指针q,指针p就是你,你的速度是1,指针q就是那个背信弃义比你快的小王八蛋,他的速度是2。如果链表中有环,设p第一次进入环时相对于环中的第一个结点的地址偏移量为a,q的为b。那么经过有限次遍历之后,p和q一定会相遇,相遇时p的指针和q的指针相等。当小王八蛋追上你时,你们相对于起点的偏移量来说是相等的。那么p和q也是这样,他们相等时,相对于头结点的偏移量也是相等的。
证明:
设环中的结点共n个,程序共循环了m次,p的速度为v1,q的速度为v2,那么很明显,p在环中走的结点数对环总结点数求余和q在环中走的结点数对总结点数求余所得余数是相等的。
即:(a + m * v1)% n = (b + m * v2)% n
设左式的最大商为k1,右式的最大商为k2,则有:
(a + m * v1) - k1n = (b + m * v2) - k2n
化简得:m = | ( (k2 - k1) * n + a - b ) / (v2 - v1) |
因为m 是整数,所以在 v2 - v1 = 1的时候等式恒成立
索引:对数据库中的一列或多列的值进行排序的结构
索引可分为四类:普通索引、主键索引、唯一索引、全文索引、聚集索引
主键索引: 在我们给一个字段设置主键的时候,它就会自动创建主键索引,用来确保每一个值都是唯一的。
唯一索引:在创建唯一索引时要不能给具有相同的索引值。
聚集索引:我们在表中添加数据的顺序,与我们创建的索引键值相同,而且一个表中只能有一个聚集索引。
普通索引:它的结构主要以B+树和哈希索引为主,主要是对数据表中的数据进行精确查找。
全文索引:它的作用是搜索数据表中的字段是不是包含我们搜索的关键字,就像搜索引擎中的模糊查询。
· 提高数据的搜索速度
· 加快表与表之间的连接速度
· 使用分组及排序子句时,可有效减少检索过程中所需的分组及排序时间,提高检索效率
· 需对其花费时间建立和维护,且维护时间与数据量成正比
· 占用存储空间
· 修改表中数据时需对索引进行动态维护
B+树的非叶子结点只包含导航信息,不包含实际的值,所有的叶子结点和相连的节点使用链表相连,便于区间查找和遍历
B+树的磁盘读写代价更低:B+树的内部节点并没有指向关键字具体信息的指针,因此其内部节点相对B树更小,如果把所有同一内部节点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多,一次性读入内存的需要查找的关键字也就越多,相对IO读写次数就降低了。
B+树的查询效率更加稳定:由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。
B+树更便于遍历:由于B+树的数据都存储在叶子结点中,分支结点均为索引,方便扫库,只需要扫一遍叶子结点即可,但是B树因为其分支结点同样存储着数据,我们要找到具体的数据,需要进行一次中序遍历按序来扫,所以B+树更加适合在区间查询的情况,所以通常B+树用于数据库索引。
B+树更适合基于范围的查询:B树在提高了IO性能的同时并没有解决元素遍历的我效率低下的问题,正是为了解决这个问题,B+树应用而生。B+树只需要去遍历叶子节点就可以实现整棵树的遍历。而且在数据库中基于范围的查询是非常频繁的,而B树不支持这样的操作或者说效率太低。
· 列与列对比(两列都使用了索引)
· 存在NULL值条件(索引列可空的话不会建立索引)
· NOT条件 <> NOT in not exists
· Like通配符
· 条件上索引列包含函数(索引在建立时可能和计算后不同,包含谓词运算,即加减乘除)
· 查询条件存在隐式数据类型的转换:如库中存储的id为number类型,查询时使用 select * from t_1 where id = ‘123’;
· 原子性:操作这些指令时,要么全部执行成功,要么全部不执行。只要其中一个指令执行失败,所有的指令都执行失败,数据进行回滚,回到执行指令前的数据状态。
· 一致性:事务的执行使数据从一个状态转换为另一个状态,但是对于整个数据的完整性保持稳定。
· 隔离性:隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。
· 持久性: 当事务正确完成后,它对于数据的改变是永久性的。
共四种,由低到高分别为:read uncommitted(读未提交)、read committed(读提交)、可重复读(repeatable read)、序列化(Serializable),MySQL默认事务隔离级别是可重复读,Oracle默认是读提交
脏读: 在一个事务处理过程里读取了另一个未提交的事务中的数据
幻读: 一个事务执行两次查询,第二次结果集包含第一次中没有或某些行已经被删除的数据,造成两次结果不一致,只是另一个事务在这两次查询中间插入或删除了数据造成的。幻读是事务非独立执行时发生的一种现象
不可重复读: 一个事务两次读取同一行的数据,结果得到不同状态的结果,中间正好另一个事务更新了该数据,两次结果相异,不可被信任
不可重复读和脏读的区别:脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。
读未提交:一个事务可以读取另一个未提交事务的数据,任何情况都无法保证,可能导致脏读、幻读、不可重复读
读提交: 一个事务要等另一个事务提交后才能读取数据。 可避免脏读问题,但仍会导致不可重复读、幻读
可重复读:事务开始读取数据时,不再允许修改操作,可避免脏读、不可重复读,仍会导致幻读
序列化: Serializable 是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。
sql优化可分为三个方面,①慢查询②索引③拆分表,这里着重讲索引方面的具体操作,主要目的就是防止索引失效,从而降低查询效率
(1)、 在表中建立索引,优先考虑where、group by使用到的字段。
(2)、 尽量避免使用select *,返回无用的字段会降低查询效率。
(3)、 尽量避免使用in 和not in,会导致数据库引擎放弃索引进行全表扫描
(4)、 尽量避免使用or,会导致数据库引擎放弃索引进行全表扫描
(5)、 尽量避免在字段开头模糊查询,会导致数据库引擎放弃索引进行全表扫描
(6)、 尽量避免进行null值的判断,会导致数据库引擎放弃索引进行全表扫描。
(7)、 尽量避免在where条件中等号的左侧进行表达式、函数操作,会导致数据库引擎放弃索引进行全表扫描。
(8)、 当数据量大时,避免使用where 1=1的条件。通常为了方便拼装查询条件,我们会默认使用该条件,数据库引擎会放弃索引进行全表扫描
聚集索引:聚集索引表示表中存储的数据按照索引的顺序存储,检索效率比非聚集索引高,但对数据更新影响较大;
非聚集索引:非聚集索引表示数据存储在一个地方,索引存储在另一个地方,索引带有指针指向数据的存储位置,非聚集索引检索效率比聚集索引低,但对数据更新影响较小。
插播一下最近面试遇到的面试题
• Propagation.REQUIRED(required):支持当前事务,如果当前有事务, 那么加入事务, 如果当前没有事务则新建一个(默认情况)
• Propagation.NOT_SUPPORTED(not_supported) : 以非事务方式执行操作,如果当前存在事务就把当前事务挂起,执行完后恢复事务(忽略当前事务);
• Propagation.SUPPORTS (supports) :如果当前有事务则加入,如果没有则不用事务。
• Propagation.MANDATORY (mandatory) :支持当前事务,如果当前没有事务,则抛出异常。(当前必须有事务)
• PROPAGATION_NEVER (never) :以非事务方式执行,如果当前存在事务,则抛出异常。(当前必须不能有事务)
• Propagation.REQUIRES_NEW (requires_new) :支持当前事务,如果当前有事务,则挂起当前事务,然后新创建一个事务,如果当前没有事务,则自己创建一个事务。
• Propagation.NESTED (nested 嵌套事务) :如果当前存在事务,则嵌套在当前事务中。如果当前没有事务,则新建一个事务自己执行(和required一样)。嵌套的事务使用保存点作为回滚点,当内部事务回滚时不会影响外部事物的提交;但是外部回滚会把内部事务一起回滚回去。(这个和新建一个事务的区别)
核心:动态代理
在应用系统调用声明@Transactional 的目标方法时,Spring Framework 默认使用 AOP 代理,在代码运行时生成一个代理对象,根据@Transactional 的属性配置信息,这个代理对象决定该声明@Transactional 的目标方法是否由拦截器 TransactionInterceptor 来使用拦截,在 TransactionInterceptor 拦截时,会在在目标方法开始执行之前创建并加入事务,并执行目标方法的逻辑, 最后根据执行情况是否出现异常,利用抽象事务管理器AbstractPlatformTransactionManager 操作数据源 DataSource 提交或回滚事务
• 聚集索引:聚集索引表示表中存储的数据按照索引的顺序存储,检索效率比非聚集索引高,但对数据更新影响较大;
• 非聚集索引:非聚集索引表示数据存储在一个地方,索引存储在另一个地方,索引带有指针指向数据的存储位置,非聚集索引检索效率比聚集索引低,但对数据更新影响较小。
• 列与列对比(两列都使用了索引)
• 存在NULL值条件(索引列可空的话不会建立索引)
• NOT条件 <> NOT in not exists
• Like通配符
• 条件上索引列包含函数(索引在建立时可能和计算后不同,包含谓词运算,即加减乘除)
• 查询条件存在隐式数据类型的转换:如库中存储的id为number类型,查询时使用 select * from t_1 where id = ‘123’;
• 缓存
• 消息队列(低精度可丢数据)
• 过滤器
• 分布式锁(分布式定时任务防止执行多次)
• 定时任务(易造成竞争浪费)
• 频率控制(zset实现,一定时间内限制单个用户的时间序列长度,超过则禁止)
• 服务发现
• 位图
• 模糊计数(概率计算,有一定误差,大约是0.81%)
• 布隆过滤器(大量新用户引入,降低缓存穿透率,降低数据库压力)
• 作用:消除高并发访问高峰,加快网站的响应速度,主要解决应用耦合,异步消息,流量削锋等问题。
• 使用场景:异步处理(注册后发送邮件和短信)、应用解耦(用户下单后订单系统需要通知库存系统)、流量削锋(秒杀)、消息通讯
下边接着来面试题