20、Netty的原理,为什么选择Netty
1、多路复用I/O与异步I/O的区别
多路复用I/O:
select、poll:在本质上没有多大差别,管理多个描述符也是进行轮询,根据描述符的状态进行处理,但是poll没有最大文件描述符数量的限制。poll和select同样存在一个缺点就是,包含大量文件描述符的数组被整体复制于用户态和内核的地址空间之间,而不论这些文件描述符是否就绪,它的开销随着文件描述符数量的增加而线性增大
epoll:是在2.6内核中提出的,是之前的select和poll的增强版本。相对于select和poll来说,epoll更加灵活,没有描述符限制。epoll使用一个文件描述符管理多个描述符,将用户关系的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间的copy只需一次。
通过红黑树和双链表数据结构,并结合回调机制,造就了epoll的高效。
一句话描述就是:三步曲。
第一步:epoll_create()系统调用。此调用返回一个句柄,之后所有的使用都依靠这个句柄来标识。红黑树存储连接的socket(每个树节点上的事件挂上事件链表)。
第二步:epoll_ctl()系统调用。通过此调用向epoll对象中添加、删除、修改感兴趣的事件,返回0标识成功,返回-1表示失败。挂载一遍事件,加回调函数,有就绪事件就往链表里面加事件。
第三部:epoll_wait()系统调用。通过此调用收集收集在epoll监控中已经发生的事件。查看链表里面有无数据。
eopll的高效原因:
上边我们学习了epoll和select/poll的相关基础,并且比较了它们的区别,发现epoll性能高效,那我们需要思考,epoll高效的原因何在。 先总结一下:epoll通过mmap+红黑树+双链表+回调机制,造就了epoll 的高效。
epoll是通过内核与用户空间mmap同一块内存实现的。mmap将用户空间的一块地址和内核空间的一块地址同时映射到相同的一块物理内存地址(不管是用户空间还是内核空间都是虚拟地址,最终要通过地址映射映射到物理地址),使得这块物理内存对内核和对用户均可见,减少用户态和内核态之间的数据交换。内核可以直接看到epoll监听的句柄,效率高。
红黑树将存储epoll所监听的套接字。上面mmap出来的内存如何保存epoll所监听的套接字,必然也得有一套数据结构,epoll在实现上采用红黑树去存储所有套接字,当添加或者删除一个套接字时(epoll_ctl),都在红黑树上去处理,红黑树本身插入和删除性能比较好,时间复杂度O(logN)。 一个fd被添加到epoll中之后(调用epoll_ctl的epoll_ctl_add模式),内核会为其生成一个对应的epitem结构对象,然后epitem会被添加到红黑树中,红黑树的作用就是在添加、删除、修改fd时,能够快速实现。
添加以及返回事件
通过epoll_ctl函数添加进来的事件fd都会被放在红黑树的某个节点内,所以,重复添加是没有用的。
建立回调+回调的逻辑是将就绪事件fd加入到双向链表中,epoll_wait调用时只需判断链表是否为空即可。
当把事件fd添加进来的时候时候会完成关键的一步,那就是该事件(fd(socket+事件类型))都会与相应的设备(网卡)驱动程序建立回调关系,当相应的事件发生后(O(1)就可判断事件是否发生),就会调用这个回调函数,该回调函数在内核中被称为:ep_poll_callback,这个回调函数的逻辑就是就所把这个事件添加到rdllist这个双向链表中。一旦有事件发生,epoll就会将该事件添加到双向链表中。那么当我们调用epoll_wait时,epoll_wait只需要检查rdlist双向链表中是否有存在注册的事件,效率非常可观。这里也需要将链表中就绪的事件复制到用户态内存中即可。
epoll_wait的工作流程:
epoll_wait调用ep_poll,当rdlist为空(无就绪fd)时挂起当前进程,直到rdlist不空时进程才被唤醒。 文件fd状态改变(buffer由不可读变为可读或由不可写变为可写),导致相应fd上的回调函数ep_poll_callback()被调用。 ep_poll_callback将相应fd对应epitem加入rdlist,导致rdlist不空,进程被唤醒,epoll_wait得以继续执行。 ep_events_transfer函数将rdlist中的epitem拷贝到txlist中,并将rdlist清空。 ep_send_events函数(很关键),它扫描txlist中的每个epitem,调用其关联fd对用的poll方法。此时对poll的调用仅仅是取得fd上较新的events(防止之前events被更新),之后将取得的events和相应的fd发送到用户空间(封装在struct epoll_event,从epoll_wait返回)。
从上边的分析中,我们就可以看到,epoll为何如此高效。 --------------------- 摘自:https://blog.csdn.net/u013679744/article/details/79188768
参考:
select、poll、epoll的原理:https://blog.csdn.net/davidsguo008/article/details/73556811
https://blog.csdn.net/u013679744/article/details/79188768
https://blog.csdn.net/lsgqjh/article/details/65629609
深入:
1、红黑树特性
参考:
教你初步了解红黑树:https://blog.csdn.net/v_JULY_v/article/details/6105630
红黑树与二叉树、平衡二叉树对比:https://www.cnblogs.com/wuchanming/p/4444961.html
2、双端链表的快速排序
----待补充
2、Netty原理
1、I/O复用模型
2、Reactor 线程模型
Reactor 是反应堆的意思,Reactor 模型是指通过一个或多个输入同时传递给服务处理器的服务请求的事件驱动处理模式。
服务端程序处理传入多路请求,并将它们同步分派给请求对应的处理线程,Reactor 模式也叫 Dispatcher 模式,即 I/O 多了复用统一监听事件,收到事件后分发(Dispatch 给某进程),是编写高性能网络服务器的必备技术之一。
Reactor 模型中有 2 个关键组成:
Reactor,Reactor 在一个单独的线程中运行,负责监听和分发事件,分发给适当的处理程序来对 IO 事件做出反应。它就像公司的电话接线员,它接听来自客户的电话并将线路转移到适当的联系人。 Handlers,处理程序执行 I/O 事件要完成的实际事件,类似于客户想要与之交谈的公司中的实际官员。Reactor 通过调度适当的处理程序来响应 I/O 事件,处理程序执行非阻塞操作。
3、Netty线程模型
主从 Rreactor 多线程模型
4、Netty功能特性图
Netty 功能特性如下:
传输服务,支持 BIO 和 NIO。 容器集成,支持 OSGI、JBossMC、Spring、Guice 容器。 协议支持,HTTP、Protobuf、二进制、文本、WebSocket 等一系列常见协议都支持。还支持通过实行编码解码逻辑来实现自定义协议。 Core 核心,可扩展事件模型、通用通信 API、支持零拷贝的 ByteBuf 缓冲对象。
5、Netty Reactor工作架构图
服务端 Netty Reactor 工作架构图
参考:
Netty原理解析:http://www.sohu.com/a/272879207_463994
Netty与Mina对比:https://blog.csdn.net/qq_33314107/article/details/81292589
21、HTTP请求流程和RPC调用流程及原理
RPC通信原理:
https://www.jianshu.com/p/78f72ccf0377
周边:
Netty IO:见上。
序列化、反序列化
序列化、反序列化原理:https://blog.csdn.net/xlgen157387/article/details/79840134
什么能序列化,什么不能?https://blog.csdn.net/xlgen157387/article/details/79840134
ProtoBuf的优缺点:https://www.jianshu.com/p/293c1e7c0a99
ZooKeeper使用及原理:
参考:
ZooKeeper使用及原理:https://blog.csdn.net/u010963948/article/details/83381757
参考:
HTTP请求原理:https://blog.csdn.net/yuntian1995/article/details/77513784
https://blog.csdn.net/lj402159806/article/details/60882615
输入URL发生了什么?https://www.cnblogs.com/daijinxue/p/6640153.html
HTTP:https://www.cnblogs.com/linjiqin/p/3560152.html
一次HTTP请求的过程:https://blog.csdn.net/hanziang1996/article/details/78982009
22、幂等性的理解,怎么实现幂等性
幂等性:就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用。如多次点击不能重复扣款等。
解决方案:
1、单次请求,判断id
2、状态查询,判断订单状态等
参考:
分布式幂等性:https://www.cnblogs.com/leechenxiang/p/6626629.html
幂等性保证:https://www.cnblogs.com/javalyy/p/8882144.html
23、过滤器和拦截器的区别
区别:
(1)、Filter需要在web.xml中配置,依赖于Servlet; (2)、Interceptor需要在SpringMVC中配置,依赖于框架; (3)、Filter的执行顺序在Interceptor之前,具体的流程见下图;
(4)、两者的本质区别:拦截器(Interceptor)是基于Java的反射机制,而过滤器(Filter)是基于函数回调。从灵活性上说拦截器功能更强大些,Filter能做的事情,都能做,而且可以在请求前,请求后执行,比较灵活。Filter主要是针对URL地址做一个编码的事情、过滤掉没用的参数、安全校验(比较泛的,比如登录不登录之类),太细的话,还是建议用interceptor。不过还是根据不同情况选择合适的。
摘自:https://blog.csdn.net/zxd1435513775/article/details/80556034
参考:
过滤器、拦截器:https://www.cnblogs.com/junzi2099/p/8022058.html
https://www.cnblogs.com/panxuejun/p/7715917.html
24、MySQL锁怎么实现?Java锁实现及优化
MySQL行锁:
在并发事务处理带来的问题中,“更新丢失”通常应该是完全避免的。但防止更新丢失,并不能单靠数据库事务控制器来解决,需要应用程序对要更新的数据加必要的锁来解决,因此,防止更新丢失应该是应用的责任。
“脏读”、“不可重复读”和“幻读”,其实都是数据库读一致性问题,必须由数据库提供一定的事务隔离机制来解决。数据库实现事务隔离的方式,基本可以分为以下两种。
一种是在读取数据前,对其加锁,阻止其他事务对数据进行修改。 另一种是不用加任何锁,通过一定机制生成一个数据请求时间点的一致性数据快照(Snapshot),并用这个快照来提供一定级别(语句级或事务级)的一致性读取。从用户的角度,好像是数据库可以提供同一数据的多个版本,因此,这种技术叫做数据多版本并发控制(MultiVersion Concurrency Control,简称MVCC或MCC),也经常称为多版本数据库。
在MVCC并发控制中,读操作可以分成两类:快照读 (snapshot read)与当前读 (current read)。快照读,读取的是记录的可见版本 (有可能是历史版本),不用加锁。当前读,读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。 在一个支持MVCC并发控制的系统中,哪些读操作是快照读?哪些操作又是当前读呢?以MySQL InnoDB为例:
1、快照读:简单的select操作,属于快照读,不加锁。(已经加了排他锁也可以这样查询记录) select * from table where ?;
2、当前读:特殊的读操作,插入/更新/删除操作,属于当前读,需要加锁。 下面语句都属于当前读,读取记录的最新版本。并且,读取之后,还需要保证其他并发事务不能修改当前记录,对读取记录加锁。其中,除了第一条语句,对读取记录加S锁 (共享锁)外,其他的操作,都加的是X锁 (排它锁)。 select * from table where ? lock in share mode; select * from table where ? for update; insert into table values (…); update table set ? where ?; delete from table where ?;
InnoDB锁:
InnoDB行锁是通过给索引上的索引项加锁来实现的。所以,
1、只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁。
2、使用不同的索引列,不同的事务也可以锁定不同的行
3、使用同一索引的不同事务,存在锁冲突。
4、条件中使用了索引,但是MySQL认为全表扫描更高效,会放弃使用索引,此时也是表锁,具体需要看执行计划。
InnoDB通过索引添加共享锁、排他锁
共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE 排他锁(X):SELECT * FROM table_name WHERE ... FOR UPDATE
另外,为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB还有两种内部使用的意向锁(Intention Locks),这两种意向锁都是表锁。
意向共享锁(IS):事务打算给数据行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。 意向排他锁(IX):事务打算给数据行加排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。
间隙锁(Next-Key锁): 当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁; 对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(Next-Key锁)。
举例来说,假如emp表中只有101条记录,其empid的值分别是 1,2,…,100,101,下面的SQL:
Select * from emp where empid > 100 for update; 1 是一个范围条件的检索,InnoDB不仅会对符合条件的empid值为101的记录加锁,也会对empid大于101(这些记录并不存在)的“间隙”加锁。
InnoDB使用间隙锁的目的,一方面是为了防止幻读,以满足相关隔离级别的要求,对于上面的例子,要是不使 用间隙锁,如果其他事务插入了empid大于100的任何记录,那么本事务如果再次执行上述语句,就会发生幻读;另外一方面,是为了满足其恢复和复制的需 要。有关其恢复和复制对锁机制的影响,以及不同隔离级别下InnoDB使用间隙锁的情况,在后续的章节中会做进一步介绍。
很显然,在使用范围条件检索并锁定记录时,InnoDB这种加锁机制会阻塞符合条件范围内键值的并发插入,这往往会造成严重的锁等待。因此,在实际应用开发中,尤其是并发插入比较多的应用,我们要尽量优化业务逻辑,尽量使用相等条件来访问更新数据,避免使用范围条件。
还要特别说明的是,InnoDB除了通过范围条件加锁时使用间隙锁外,如果使用相等条件请求给一个不存在的记录加锁,InnoDB也会使用间隙锁!
参考:
MySQL锁详解:https://blog.csdn.net/soonfly/article/details/70238902
MySQL的行锁与表锁:https://blog.csdn.net/hxpjava1/article/details/79407961
锁算法:
参考:https://segmentfault.com/a/1190000014133576
锁优化: Innodb行锁优化建议
尽可能让所有的数据检索都通过索引来完成,从而避免Innodb因为无法通过索引键加锁而升级为表级锁定; 合理设计索引,让Innodb在索引键上面加锁尽可能准确,尽可能的缩小锁定范围,避免造成不必要的锁定而影响其他Query的执行; 尽可能减少基于范围的数据检索过滤条件,避免间隙锁带来的负面影响而锁定了不该锁定的记录; 尽量控制事务的大小,减少锁定的资源量和锁定时间长度;
尽量使用较低的隔离级别; 精心设计索引,并尽量使用索引访问数据,使加锁更精确,从而减少锁冲突的机会; 选择合理的事务大小,小事务发生锁冲突的几率也更小; 给记录集显式加锁时,最好一次性请求足够级别的锁。比如要修改数据的话,最好直接申请排他锁,而不是先申请共享锁,修改时再请求排他锁,这样容易产生死锁; 不同的程序访问一组表时,应尽量约定以相同的顺序访问各表,对一个表而言,尽可能以固定的顺序存取表中的行。这样可以大大减少死锁的机会; 尽量用相等条件访问数据,这样可以避免间隙锁对并发插入的影响; 不要申请超过实际需要的锁级别;除非必须,查询时不要显示加锁; 对于一些特定的事务,可以使用表锁来提高处理速度或减少死锁的可能。
参考:
MySQL锁原理深入:https://blog.csdn.net/zcl_love_wx/article/details/81983267
MySQL锁优化:https://blog.csdn.net/andong154564667/article/details/81019170
MVCC与Undo Redo日志:
MySQL InnoDB引擎,写数据前,先把当前数据写到Undo日志,便于多版本控制或者回滚保证事务的原子性,之后把更新后的数据写入Redo日志,产生脏页,后面由主线程写入磁盘。写的时候为了避免,redo日志写一半出现故障,进行了二次写的设计,先写入二次写缓存,然后在写入磁盘。如果写磁盘出现故障,也可以从二次写缓存中恢复过来。
MVCC实现原理:
MySql每行记录有三个隐藏字段,通过指向回滚版本的字段或删除版本标识,实现多版本的读取。
参考:https://blog.csdn.net/Jeaforea/article/details/82498120
MySQL索引优化及原理:
1、区分:聚簇索引、非聚簇索引
索引分为聚簇索引和非聚簇索引两种,聚簇索引是按照数据存放的物理位置为顺序的,而非聚簇索引就不一样了;聚簇索引能提高多行检索的速度,而非聚簇索引对于单行的检索很快
mysql中,不同的存储引擎对索引的实现方式不同,大致说下MyISAM和InnoDB两种存储引擎。 MyISAM的B+Tree的叶子节点上的data,并不是数据本身,而是数据存放的地址。主索引和辅助索引没啥区别,只是主索引中的key一定得是唯一的。这里的索引都是非聚簇索引。 MyISAM还采用压缩机制存储索引,比如,第一个索引为“her”,第二个索引为“here”,那么第二个索引会被存储为“3,e”,这样的缺点是同一个节点中的索引只能采用顺序查找。
InnoDB的数据文件本身就是索引文件,B+Tree的叶子节点上的data就是数据本身,key为主键,这是聚簇索引。非聚簇索引,叶子节点上的data是主键(所以聚簇索引的key,不能过长)。为什么存放的主键,而不是记录所在地址呢,理由相当简单,因为记录所在地址并不能保证一定不会变,但主键可以保证。 至于为什么主键通常建议使用自增id呢? 答:聚簇索引的数据的物理存放顺序与索引顺序是一致的,即:只要索引是相邻的,那么对应的数据一定也是相邻地存放在磁盘上的。如果主键不是自增id,那么可以想象,它会干些什么,不断地调整数据的物理地址、分页,当然也有其他一些措施来减少这些操作,但却无法彻底避免。但,如果是自增的,那就简单了,它只需要一页一页地写,索引结构相对紧凑,磁盘碎片少,效率也高。
使用推荐:
摘自:https://www.cnblogs.com/wyy123/p/6269875.html
2、索引类型:
1、主键索引:即主索引,根据主键pk_clolum(length)建立索引,不允许重复,不允许空值;
ALTER TABLE 'table_name' ADD PRIMARY KEY('col'); 2、唯一索引:用来建立索引的列的值必须是唯一的,允许空值
ALTER TABLE 'table_name' ADD UNIQUE('col'); 3、普通索引:用表中的普通列构建的索引,没有任何限制
ALTER TABLE 'table_name' ADD INDEX index_name('col'); 4、全文索引:用大文本对象的列构建的索引(下一部分会讲解)
ALTER TABLE 'table_name' ADD FULLTEXT('col'); 5、组合索引:用多个列组合构建的索引,这多个列中的值不允许有空值
ALTER TABLE 'table_name' ADD INDEX index_name('col1','col2','col3'); *遵循“最左前缀”原则,把最常用作为检索或排序的列放在最左,依次递减,组合索引相当于建立了col1,col1col2,col1col2col3三个索引,而col2或者col3是不能使用索引的。
3、索引原理
MySQL InnoDB的索引:B+树。
为什么使用B+树?
一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上。这样的话,索引查找过程中就要产生磁盘I/O消耗,相对于内存存取,I/O存取的消耗要高几个数量级,所以评价一个数据结构作为索引的优劣最重要的指标就是在查找过程中磁盘I/O操作次数的渐进复杂度。换句话说,索引的结构组织要尽量减少查找过程中磁盘I/O的存取次数。
而B+树I/O存取次数最少。
BTree索引 BTree是平衡搜索多叉树,设树的度为d(d>1),高度为h,那么BTree要满足以一下条件:
每个叶子结点的高度一样,等于h;
每个非叶子结点由n-1个key和n个指针point组成,其中d<=n<=2d,key和point相互间隔,结点两端一定是key;
叶子结点指针都为null;
非叶子结点的key都是[key,data]二元组,其中key表示作为索引的键,data为键值所在行的数据;
BTree的结构如下:
在BTree的机构下,就可以使用二分查找的查找方式,查找复杂度为h*log(n),一般来说树的高度是很小的,一般为3左右,因此BTree是一个非常高效的查找结构。
B+Tree索引 B+Tree是BTree的一个变种,设d为树的度数,h为树的高度,B+Tree和BTree的不同主要在于:
B+Tree中的非叶子结点不存储数据,只存储键值;
B+Tree的叶子结点没有指针,所有键值都会出现在叶子结点上,且key存储的键值对应的数据的物理地址;
B+Tree的结构如下:
一般来说B+Tree比BTree更适合实现外存的索引结构,因为存储引擎的设计专家巧妙的利用了外存(磁盘)的存储结构,即磁盘的一个扇区是整数倍的page(页),页是存储中的一个单位,通常默认为4K,因此索引结构的节点被设计为一个页的大小,然后利用外存的“预读取”原则,每次读取的时候,把整个节点的数据读取到内存中,然后在内存中查找,已知内存的读取速度是外存读取I/O速度的几百倍,那么提升查找速度的关键就在于尽可能少的磁盘I/O,那么可以知道,每个节点中的key个数越多,那么树的高度越小,需要I/O的次数越少,因此一般来说B+Tree比BTree更快,因为B+Tree的非叶节点中不存储data,就可以存储更多的key。
带顺序索引的B+TREE 很多存储引擎在B+Tree的基础上进行了优化,添加了指向相邻叶节点的指针,形成了带有顺序访问指针的B+Tree,这样做是为了提高区间查找的效率,只要找到第一个值那么就可以顺序的查找后面的值。
MySQL聚簇索引与非聚簇对比:
MyISAM——非聚簇索引
MyISAM存储引擎采用的是非聚簇索引,非聚簇索引的主索引和辅助索引几乎是一样的,只是主索引不允许重复,不允许空值,他们的叶子结点的key都存储指向键值对应的数据的物理地址。 非聚簇索引的数据表和索引表是分开存储的。 非聚簇索引中的数据是根据数据的插入顺序保存。因此非聚簇索引更适合单个数据的查询。插入顺序不受键值影响。 只有在MyISAM中才能使用FULLTEXT索引。 *最开始我一直不懂既然非聚簇索引的主索引和辅助索引指向相同的内容,为什么还要辅助索引这个东西呢,后来才明白索引不就是用来查询的吗,用在那些地方呢,不就是WHERE和ORDER BY 语句后面吗,那么如果查询的条件不是主键怎么办呢,这个时候就需要辅助索引了。
InnoDB——聚簇索引
聚簇索引的主索引的叶子结点存储的是键值对应的数据本身,辅助索引的叶子结点存储的是键值对应的数据的主键键值。因此主键的值长度越小越好,类型越简单越好。 聚簇索引的数据和主键索引存储在一起。 聚簇索引的数据是根据主键的顺序保存。因此适合按主键索引的区间查找,可以有更少的磁盘I/O,加快查询速度。但是也是因为这个原因,聚簇索引的插入顺序最好按照主键单调的顺序插入,否则会频繁的引起页分裂,严重影响性能。 在InnoDB中,如果只需要查找索引的列,就尽量不要加入其它的列,这样会提高查询效率。 *使用主索引的时候,更适合使用聚簇索引,因为聚簇索引只需要查找一次,而非聚簇索引在查到数据的地址后,还要进行一次I/O查找数据。
*因为聚簇辅助索引存储的是主键的键值,因此可以在数据行移动或者页分裂的时候降低委会成本,因为这时不用维护辅助索引。但是辅助索引会占用更多的空间。
*聚簇索引在插入新数据的时候比非聚簇索引慢很多,因为插入新数据时需要减压主键是否重复,这需要遍历主索引的所有叶节点,而非聚簇索引的叶节点保存的是数据地址,占用空间少,因此分布集中,查询的时候I/O更少,但聚簇索引的主索引中存储的是数据本身,数据占用空间大,分布范围更大,可能占用好多的扇区,因此需要更多次I/O才能遍历完毕。
下图可以形象的说明聚簇索引和非聚簇索引的区别
摘自:https://blog.csdn.net/tongdanping/article/details/79878302
4、覆盖索引(Covering Indexes):
如果索引包含满足查询的所有数据,就称为覆盖索引。覆盖索引是一种非常强大的工具,能大大提高查询性能。只需要读取索引而不用读取数据有以下一些优点: (1)索引项通常比记录要小,所以MySQL访问更少的数据; (2)索引都按值的大小顺序存储,相对于随机访问记录,需要更少的I/O; (3)大多数据引擎能更好的缓存索引。比如MyISAM只缓存索引。 (4)覆盖索引对于InnoDB表尤其有用,因为InnoDB使用聚集索引组织数据,如果二级索引中包含查询所需的数据,就不再需要在聚集索引中查找了。 覆盖索引不能是任何索引,只有B-TREE索引存储相应的值。而且不同的存储引擎实现覆盖索引的方式都不同,并不是所有存储引擎都支持覆盖索引(Memory和Falcon就不支持)。 对于索引覆盖查询(index-covered query),使用EXPLAIN时,可以在Extra一列中看到“Using index”。例如,在sakila的inventory表中,有一个组合索引(store_id,film_id),对于只需要访问这两列的查询,MySQL就可以使用索引,如下:
mysql> EXPLAIN SELECT store_id, film_id FROM sakila.inventory\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: inventory
type: index
possible_keys: NULL
key: idx_store_id_film_id
key_len: 3
ref: NULL
rows: 5007
Extra: Using index
1 row in set (0.17 sec)
在大多数引擎中,只有当查询语句所访问的列是索引的一部分时,索引才会覆盖。但是,InnoDB不限于此,InnoDB的二级索引(辅助索引、非聚集索引)在叶子节点中存储了primary key的值。因此,sakila.actor表使用InnoDB,而且对于是last_name上有索引,所以,索引能覆盖那些访问actor_id的查询,如:
mysql> EXPLAIN SELECT actor_id, last_name
-> FROM sakila.actor WHERE last_name = 'HOPPER'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: actor
type: ref
possible_keys: idx_actor_last_name
key: idx_actor_last_name
key_len: 137
ref: const
rows: 2
Extra: Using where; Using index
摘自:https://blog.csdn.net/tongdanping/article/details/79878302
5、索引使用建议:
五、索引的使用策略
什么时候要使用索引?
主键自动建立唯一索引; 经常作为查询条件在WHERE或者ORDER BY 语句中出现的列要建立索引; 作为排序的列要建立索引; 查询中与其他表关联的字段,外键关系建立索引 高并发条件下倾向组合索引;
什么时候不要使用索引?
经常增删改的列不要建立索引; 有大量重复的列不建立索引; 表记录太少不要建立索引; *在组合索引中不能有列的值为NULL,如果有,那么这一列对组合索引就是无效的; *在一个SELECT语句中,索引只能使用一次,如果在WHERE中使用了,那么在ORDER BY中就不要用了; *LIKE操作中,'