1. Mysql索引在什么情况下会失效
- 查询条件包含
or
,可能导致索引失效。 - 字段类型是字符串,
where
时一定用引号括起来,否则索引失效。 like
通配符可能导致索引失效。- 联合索引,查询时的条件列不是联合索引中的第一个列,索引失效。
- 在索引列上使用mysql的内置函数,索引失效。
- 对索引列运算(如,
+
、-
、*
、/
),索引失效。 - 索引字段上使用(
!=
或者< >
,not in
)时,可能会导致索引失效。 - 索引字段上使用
is null
,is not null
,可能导致索引失效。 - 左连接查询或者右连接查询查询关联的字段编码格式不一样,可能导致索引失效。
- mysql估计使用全表扫描要比使用索引快,则不使用索引。
2. MySql的存储引擎InnoDB与MyISAM的区别
- InnoDB支持事务,MyISAM不支持事务。
- InnoDB支持外键,MyISAM不支持外键。
- InnoDB 支持 MVCC(多版本并发控制),MyISAM 不支持。
select count(*) from table
时,MyISAM更快,因为它有一个变量保存了整个表的总行数,可以直接读取,InnoDB就需要全表扫描。- Innodb不支持全文索引,而MyISAM支持全文索引(5.7以后的InnoDB也支持全文索引)。
- InnoDB支持表、行级锁,而MyISAM支持表级锁。
- InnoDB表必须有主键,而MyISAM可以没有主键。
- Innodb表需要更多的内存和存储,而MyISAM可被压缩,存储空间较小。
- Innodb按主键大小有序插入,MyISAM记录插入顺序是,按记录插入顺序保存。
- InnoDB 存储引擎提供了具有提交、回滚、崩溃恢复能力的事务安全,与 MyISAM 比 InnoDB 写的效率差一些,并且会占用更多的磁盘空间以保留数据和索引。
3. mysql在项目中的优化场景,慢查询解决等
面对慢查询,首先想到的就是加索引。一个加了索引的SQL,是怎么执行查找的。还有就是order by
,group by
原理,深分页等等,都跟慢查询息息相关。最后就是慢查询的排查解决手段:打开慢查询日志slow_query_log
,确认SQL语句是否占用过多资源,用explain
查询执行计划、对group by
、order by
、join
等语句优化,如果数据量实在太大,是否考虑分库分表等等。
4. Mysql有什么索引,索引模型是什么
一般使用都是B+树索引,详细理解的话,可以看这篇文章:MySQL索引底层:B+树详解。
5. B-树与B+树的区别?为什么不用红黑树
- B-树内部节点是保存数据的;而B+树内部节点是不保存数据的,只作索引作用,它的叶子节点才保存数据。
- B+树相邻的叶子节点之间是通过链表指针连起来的,B-树却不是。
- 查找过程中,B-树在找到具体的数值以后就结束,而B+树则需要通过索引找到叶子结点中的数据才结束。
- B-树中任何一个关键字出现且只出现在一个结点中,而B+树可以出现多次。
为什么索引结构默认使用B+树,而不是B-Tree,Hash哈希,二叉树,红黑树?
- Hash哈希,只适合等值查询,不适合范围查询。
- 一般二叉树,可能会特殊化为一个链表,相当于全表扫描。
- 红黑树,是一种特化的平衡二叉树,MySQL 数据量很大的时候,索引的体积也会很大,内存放不下的而从磁盘读取,树的层次太高的话,读取磁盘的次数就多了。
- B-Tree,叶子节点和非叶子节点都保存数据,相同的数据量,B+树更矮壮,也是就说,相同的数据量,B+树数据结构,查询磁盘的次数会更少。
6. Mysql主从同步怎么做
MySQL主从复制原理:
主库的更新SQL(update、insert、delete)被写到binlog
从库发起连接,连接到主库。
此时主库创建一个binlog dump thread,把binlog的内容发送到从库。
从库启动之后,创建一个I/O线程,读取主库传过来的binlog内容并写入到relay log
从库还会创建一个SQL线程,从relay log里面读取内容,从ExecMasterLog_Pos位置开始执行读取到的更新事件,将更新内容写入到slave的db
7. 乐观锁与悲观锁的区别?
- 悲观锁:一个事务拥有(获得)悲观锁后,其他任何事务都不能对数据进行修改。
- 乐观锁:它认为数据的变动不会太频繁。因此,它允许多个事务同时对数据进行变动。实现方式:乐观锁一般会使用版本号机制或CAS算法实现。
8. 聊聊binlog日志
binlog是归档日志,属于MySQL Server层的日志。可以实现主从复制和数据恢复两个作用。当需要恢复数据时,可以取出某个时间范围内的binlog进行重放恢复即可。
binlog 日志有三种格式,分别是statement,row和mixed。
9. Redis 持久化有哪几种方式,怎么选?
Redis提供了两种持久化方式,RDB和AOF。
9.1 AOF 持久化
AOF(append only file) 持久化,采用日志的形式来记录每个写操作,追加到AOF文件的末尾。
9.2 RDB
RDB,就是把内存数据以快照的形式保存到磁盘上。
9.3 如何选择RDB和AOF
- 如果数据不能丢失,RDB和AOF混用。
- 如果只作为缓存使用,可以承受几分钟的数据丢失的话,可以只使用RDB。
- 如果只使用AOF,优先使用everysec的写回策略。
10. Redis 主从同步是怎样的过程?
Redis主从同步包括三个阶段:
第一阶段:主从库间建立连接、协商同步。
第二阶段:主库把数据同步到从库,从库收到数据后,完成本地加载。
第三阶段,主库把新写的命令,发送到从库。
11. 聊聊Redis的zset,它是怎么实现的?
zset是Redis常用数据类型之一,它的成员是有序排列的,一般用于排行榜类型的业务场景。
它的底层内部编码:ziplist(压缩列表)、skiplist(跳跃表)
12. Redis 过期策略和内存淘汰策略
12.1 Redis的过期策略
一般有定时过期、惰性过期、定期过期三种。
12.2 Redis 内存淘汰策略
- volatile-lru:当内存不足以容纳新写入数据时,从设置了过期时间的key中使用LRU(最近最少使用)算法进行淘汰;
- allkeys-lru:当内存不足以容纳新写入数据时,从所有key中使用LRU(最近最少使用)算法进行淘汰。
- volatile-lfu:4.0版本新增,当内存不足以容纳新写入数据时,在过期的key中,使用LFU(最少访问算法)进行删除key。
- allkeys-lfu:4.0版本新增,当内存不足以容纳新写入数据时,从所有key中使用LFU算法进行淘汰;
- volatile-random:当内存不足以容纳新写入数据时,从设置了过期时间的key中,随机淘汰数据;
- allkeys-random:当内存不足以容纳新写入数据时,从所有key中随机淘汰数据。
- volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的key中,根据过期时间进行淘汰,越早过期的优先被淘汰;
- noeviction:默认策略,当内存不足以容纳新写入数据时,新写入操作会报错。
13. Hashmap 是怎样实现的?为什么要用红黑树,而不用平衡二叉树?为什么在1.8中链表大于8时会转红黑树?HashMap是线性安全的嘛?如何保证安全?
13.1 Hashmap 是怎样实现的?
JDK1.7 Hashmap的底层数据结构是数组+链表
JDK1.8 Hashmap的底层数据结构是数组+链表+红黑树
13.2 为什么要用红黑树,为什么不用二叉树?为什么不用平衡二叉树?
红黑树是一种平衡的二叉树,其插入、删除、查找的最坏时间复杂度都为 O(logn),避免了二叉树最坏情况下的O(n)时间复杂度。
13.3 为什么在1.8中链表大于8时会转红黑树?
红黑树的平均查找长度是log(n),如果长度为8,平均查找长度为log(8)=3,链表的平均查找长度为n/2,当长度为8时,平均查找长度为8/2=4,这才有转换成树的必要;链表长度如果是小于等于6,6/2=3,而log(6)=2.6,虽然速度也很快的,但是转化为树结构和生成树的时间并不会太短。
13.4 HashMap是线性安全的嘛?如何保证安全?
HashMap不是线程安全的,多线程下扩容死循环。可以使用HashTable、Collections.synchronizedMap、以及 ConcurrentHashMap 可以实现线程安全。
14. select和epoll的区别
14.1 IO多路复用之select
应用进程通过调用select函数,可以同时监控多个fd,在select函数监控的fd中,只要有任何一个数据状态准备就绪了,select函数就会返回可读状态,这时应用进程再发起recvfrom请求去读取数据。
14.2 IO多路复用之epoll
epoll先通过epoll_ctl()来注册一个fd(文件描述符),一旦基于某个fd就绪时,内核会采用回调机制,迅速激活这个fd,当进程调用epoll_wait()时便得到通知。这里去掉了遍历文件描述符的坑爹操作,而是采用监听事件回调的机制。这就是epoll的亮点。
15. http与https的区别,https的原理,如何加密的?
http与https的区别
HTTP,即超文本传输协议,是一个基于TCP/IP通信协议来传递明文数据的协议。HTTPS= HTTP+SSL/TLS,可以理解Https是身披SSL(Secure Socket Layer,安全套接层)的HTTP。
https的原理,如何加密的
客户端发起Https请求,连接到服务器的443端口。服务器必须要有一套数字证书(证书内容有公钥、证书颁发机构、失效日期等)。服务器将自己的数字证书发送给客户端(公钥在证书里面,私钥由服务器持有)。客户端收到数字证书之后,会验证证书的合法性。如果证书验证通过,就会生成一个随机的对称密钥,用证书的公钥加密。客户端将公钥加密后的密钥发送到服务器。服务器接收到客户端发来的密文密钥之后,用自己之前保留的私钥对其进行非对称解密,解密之后就得到客户端的密钥,然后用客户端密钥对返回数据进行对称加密,酱紫传输的数据都是密文啦。服务器将加密后的密文返回到客户端。客户端收到后,用自己的密钥对其进行对称解密,得到服务器返回的数据。
16. Raft算法原理
Raft 算法是分布式系统开发首选的共识算法,它通过“一切以领导者为准”的方式,实现一系列值的共识和各节点日志的一致。
16.1 Raft 角色
- 跟随者(Follower)
- 候选人(Candidate)
- 领导者(Leader)
16.2 领导选举过程
1.在初始时,集群中所有的节点都是Follower状态,都被设定一个随机选举超时时间(一般150ms-300ms):
- 如果Follower在规定的超时时间,都没有收到来自Leader的心跳,它就发起选举:将自己的状态切为 Candidate,增加自己的任期编号,然后向集群中的其它Follower节点发送请求,询问其是否选举自己成为Leader:
其他节点收到候选人A的请求投票消息后,如果在编号为1的这届任期内还没有进行过投票,那么它将把选票投给节点A,并增加自己的任期编号:
当收到来自集群中过半节点的接受投票后,A节点即成为本届任期内 Leader,他将周期性地发送心跳消息,通知其他节点我是Leader,阻止Follower发起新的选举:
16.2 日志复制
当系统leader收到一个来自客户端的写请求,就会添加一个log entry(日志项)到本地日志。Leader通过日志复制(AppendEntries)RPC 消息,将日志项并行复制到集群其它Follower节点。如果Leader接收到大多数的“复制成功”响应后,它将日志项应用到自己的状态机,并返回成功给客户端。相反没有收到大多数的“复制成功”响应,那么就返回错误给客户端;当Follower接收到心跳信息,或者新的AppendEntries消息后,如果发现Leader已经提交了某条日志项,而自己还没应用,那么Follower就会将这条日志项应用到本地的状态机中。
Raft算法,Leader是通过强制Follower直接复制自己的日志项,来处理不一致日志,从而最终实现了集群各节点日志的一致。
17. 消息中间件如何做到高可用
消息中间件如何保证高可用呢?单机是没有高可用可言的,高可用都是对集群来说的,一起看下kafka的高可用吧。
Kafka 的基础集群架构,由多个broker组成,每个broker都是一个节点。当你创建一个topic时,它可以划分为多个partition,而每个partition放一部分数据,分别存在于不同的 broker 上。也就是说,一个 topic 的数据,是分散放在多个机器上的,每个机器就放一部分数据。
18. 消息队列怎么保证不丢消息的
一个消息从生产者产生,到被消费者消费,主要经过这3个过程:生产者保证不丢消息、存储端不丢消息、消费者不丢消息。
19. Redis如何保证高可用?聊聊Redis的哨兵机制
主从模式中,一旦主节点由于故障不能提供服务,需要人工将从节点晋升为主节点,同时还要通知应用方更新主节点地址。显然,多数业务场景都不能接受这种故障处理方式。Redis从2.8开始正式提供了Redis Sentinel(哨兵)架构来解决这个问题。
20. 无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的最长子串的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
这道题可以使用滑动窗口来实现。滑动窗口就是维护一个窗口,不断滑动,然后更新答案。
滑动窗口的大致逻辑框架,伪代码如下:
int left =0,right = 0;
while (right < s.size()){
//增大窗口
window.add(s[right]);
right++;
while (window needs shrink){
//缩小窗口
window.remove (s[left]);
left ++;
}
}
解法流程如下:
首先呢,就是获取原字符串的长度。
接着维护一个窗口(数组、哈希、队列)
窗口一步一步向右扩展
窗口在向右扩展滑动过程,需要判断左边是否需要缩减
最后比较更新答案
完整代码如下:
int lengthOfLongestSubstring(String s){
//获取原字符串的长度
int len = s.length();
//维护一个哈希集合的窗口
Set windows = new HashSet<>();
int left=0,right =0;
int res =0;
while(right<len){
char c = s.charAt(right);
//窗口右移
right++;
//判断是否左边窗口需要缩减,如果已经包含,那就需要缩减
while(windows.contains(c)){
windows.remove(s.charAt(left));
left++;
}
windows.add(c);
//比较更新答案
res = Math.max(res,windows.size());
}
return res;
}
之前写过一篇滑动窗口解析,大家有兴趣可以看下哈:
leetcode必备算法:聊聊滑动窗口
参考与感谢
分布式理论之分布式一致性:Raft算法原理[2]、一文搞懂Raft算法[3]
参考资料
[1]分布式一致性:Raft算法原理: https://www.tpvlog.com/article/66
[2]分布式理论之分布式一致性:Raft算法原理: https://www.tpvlog.com/article/66
[3]一文搞懂Raft算法: https://www.cnblogs.com/xybaby/p/10124083.html
发表评论: