面试题整理 2
总结了本次面试遇到的值得整理记录的面试题。
目录
变量赋值判断
变量+=判断
Foreach使用
Mysql优化策略
合理的索引设计
查询优化
数据表结构设计
配置优化
合理使用事务
定期维护数据库
使用缓存
监控与性能分析
Redis主从复制
介绍
配置
示例
Redis 数据类型及应用
string
常用命令
应用场景
hash
常用命令
应用场景
list
常用命令
应用场景
set
常用命令
应用场景
zset
常用命令
应用场景
Mysql 事务级别
1.READ UNCOMMITTED
2.READ COMMITTED
3.REPEATABLE READ
4.SERIALIZABLE
大数据量统计
Mysql 锁
行级锁
表级锁
主键锁
间隙锁
借鉴文章
变量赋值判断
$a = null;
$b = $a;
$c = false;
$d = $c;
var_dump(isset($a), empty($b), isset($c), empty($d));
结果:
bool(false) bool(true) bool(true) bool(true)
变量+=判断
$a = [0, 1, 2, 3];
$b = [1, 2, 3, 4];
$a += $b;
print_r($a);
结果:
Array ( [0] => 0 [1] => 1 [2] => 2 [3] => 3 )
Foreach使用
$arr = [1, 2, 3, 4];
foreach ($arr as &$V) {
}
foreach ($arr as $v) {
}
print_r($arr);
结果:
Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 )
Mysql优化策略
合理的索引设计
使用索引:在常用的查询条件(如WHERE、JOIN、ORDER BY 和 GROUP BY)上创建索引。
复合索引:对多个列的查询条件创建复合索引,以减少索引的数量和提高查询性能。
避免过度索引:过多的索引会增加写入操作的负担,影响性能,因此要合理选择索引。
查询优化
使用 EXPLAIN:在运行查询之前,使用 EXPLAIN 了解查询的执行计划,帮助识别瓶颈。
避免 SELECT *:选择必要的列,减少返回的数据量,提高查询效率。
使用 WHERE 条件:尽量添加 WHERE 条件,减少读取的数据量。
小表驱动大表: 尽量使用小表去关联大表,减少关联数据
数据表结构设计
合理的数据类型:选择合适的数据类型,可以减少存储空间并提高性能。例如,尽量使用 INT 而不是 BIGINT,以及选择最合适的字符串类型。
规范化与反规范化:在设计表结构时根据实际情况考虑规范化(消除冗余)与反规范化(提高查询效率)。
分区表(Partitioning):对于大型表,使用分区可以提高查询效率和管理性能。
大表进行拆分:比如一个大表,里面有很多的text,MEDIUMTEXT,LONGTEXT,这种可以抽取关键字段,然后引用大表的主键ID,方便报表需求开发。
配置优化
调整内存设置:根据应用程序的需求,适当调整 MySQL 的内存配置,如 innodb_buffer_pool_size(对于 InnoDB 存储引擎)来提高性能。
设置查询缓存:对于频繁查询的结果,可以启用查询缓存(虽然在新的 MySQL 版本中,查询缓存已被弃用,需谨慎使用)。
监控和调优服务器参数:定期监控 MySQL 的性能指标,并根据需求调整配置,如连接数、线程数等。
合理使用事务
控制事务的范围:尽量将事务控制在最小的范围内,减少对资源的占用。
使用适当的事务隔离级别:根据需求选择合适的事务隔离级别,以平衡性能与一致性。
IO和HTTP不要在同一个事务之内:这么做是为了避免,事务在回滚的时候,某一操作不可逆。
定期维护数据库
分析和优化表:定期运行 ANALYZE TABLE 和 OPTIMIZE TABLE 来更新统计信息和整理表的碎片。
清理无用数据:定期删除或归档旧数据,保持数据库的有效性和性能。
使用缓存
应用层缓存:使用 Redis 或 Memcached 等缓存系统来减轻数据库的负担,提高响应速度。
数据缓存:将频繁访问的数据缓存在内存中,减少对数据库的直接查询。
监控与性能分析
使用监控工具:借助如 MySQL Enterprise Monitor、Percona Toolkit 等工具监控数据库性能。
慢查询日志:启用慢查询日志以识别性能瓶颈,并对相关查询进行优化。
Redis主从复制
介绍
Redis主从复制是一个多Redis实例进行数据同步的过程,其中一个实例是主实例(Master),其他实例是从实例(Slave)。主实例负责处理命令请求,而从实例则 periodically 地从主实例拉取数据副本。
配置
要配置Redis主从复制,需要在从实例的配置文件中设置 slaveof 指令,指向主实例的IP和端口。
例如,假设主实例运行在IP 192.168.1.100 的6379端口上,可以在从实例的配置文件中添加如下行:
slaveof 192.168.1.100 6379
或者,你也可以在从实例启动时通过命令行参数设置:
redis-server --slaveof 192.168.1.100 6379
当配置生效后,从实例会连接到主实例,并开始接收数据。如果主实例发生故障,从实例可以配置为自动进行故障转移,这需要设置 slave-serve-stale-data 为 yes 并启用 slave-read-only 选项。
示例
以下是一个简单的例子,展示如何在Redis配置文件中启用主从复制:
# 主实例的配置文件(无需更改)
# 从实例的配置文件
slaveof 192.168.1.100 6379
slave-serve-stale-data yes
slave-read-only yes
记得在修改配置后重启Redis实例以使配置生效。
Redis 数据类型及应用
string
常用命令
除了get、set、incr、decr mget等操作外,Redis还提供了下面一些操作:
获取字符串长度
往字符串append内容
设置和获取字符串的某一段内容
设置及获取字符串的某一位(bit)
批量设置一系列字符串的内容
应用场景
String是最常用的一种数据类型,普通的key/value存储都可以归为此类,value其实不仅是String,
也可以是数字:比如想知道什么时候封锁一个IP地址(访问超过几次)。INCRBY命令让这些变得很容易,通过原子递增保持计数。
hash
常用命令
hget,hset,hgetall 等。
应用场景
比如我们要存储一个用户信息对象数据,包含以下信息:
用户ID,为查找的key,
存储的value用户对象包含姓名name,年龄age,生日birthday 等信息
list
常用命令
lpush,rpush,lpop,rpop,lrange,BLPOP(阻塞版)等。
应用场景
可以轻松地实现最新消息排行等功能。
List的另一个应用就是消息队列,可以利用Lists的PUSH操作,将任务存在List中,然后工作线程再用POP操作将任务取出进行执行。
set
常用命令
sadd,srem,spop,sdiff ,smembers,sunion 等。
应用场景
Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的。set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。
比如在微博应用中,每个人的好友存在一个集合(set)中,这样求两个人的共同好友的操作,可能就只需要用求交集命令即可。
Redis还为集合提供了求交集、并集、差集等操作
zset
常用命令
zadd,zrange,zrem,zcard等
应用场景
以某个条件为权重,比如按顶的次数排序.
ZREVRANGE命令可以用来按照得分来获取前100名的用户,ZRANK可以用来获取用户排名,非常直接而且操作容易。
Redis sorted set的使用场景与set类似,区别是set不是自动有序的,而sorted set可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序。
比如:全班同学成绩,value可以是同学的学号,而score就可以是其考试得分,这样数据插入集合的,就已经进行了天然的排序。
Mysql 事务级别
在 MySQL中事务的隔离级别有以下 4 种:
读未提交(READ UNCOMMITTED)
读已提交(READ COMMITTED)
可重复读(REPEATABLE READ)
序列化(SERIALIZABLE)
MySQL 默认的事务隔离级别是可重复读,这4种隔离级别的说明如下。
1.READ UNCOMMITTED
读未提交,也叫未提交读,该隔离级别的事务可以看到其他事务中未提交的数据。该隔离级别因为可以读取到其他事务中未提交的数据,而未提交的数据可能会发生回滚,因此把该级别读取到的数据称之为脏数据,把这个问题称之为脏读。
2.READ COMMITTED
读已提交,也叫提交读,该隔离级别的事务能读取到已经提交事务的数据,因此它不会有脏读问题。但由于在事务的执行中可以读取到其他事务提交的结果,所以在不同时间的相同 SQL查询中,可能会得到不同的结果,这种现象叫做不可重复读。
3.REPEATABLE READ
可重复读,是MySQL的默认事务隔离级别,它能确保同一事务多次查询的结果一致。但也会有新的问题,比如此级别的事务正在执行时,另一个事务成功的插入了某条数据,但因为它每次查询的结果都是一样的,所以会导致查询不到这条数据,自己重复插入时又失败(因为唯一约束的原因)。明明在事务中查询不到这条信息,但就是插入不进去,这就叫幻读 (Phantom Read)。
4.SERIALIZABLE
序列化,事务最高隔离级别,它会强制事务排序,使之不会发生冲突,从而解决了脏读、不可重复读和幻读问题,但因为执行效率低,所以真正使用的场景并不多。
大数据量统计
一亿条订单数据属于1000个商户,取出订单量最多的前10家商户
如果直接使用一条sql来查出来,
无疑是非常慢并且损耗系统性能的,
设置数据库可能会崩溃。
可以分为两步来执行。
下面介绍实现思路:
首先数据表增加字段
在订单表中增加一个是否处理的标识,
在商户表中增加一个订单量字段用来存储该商户的下单量;
第一步分批次的每次拿一定订单数据,统计后更新相应商户下单量,并标识订单已被处理;最后把所有现有订单处理统计完成。
第二步在下单时维护一个商户下单量字段,
这样最后统计商户订单量前10只需要:
select id,name, order_num from member order by order_num desc limit 10;
即可达到效果。
Mysql 锁
行级锁
表级锁
主键锁
主键锁是为了保护表中具体的一条记录,当对表中的一条记录进行更新(UPDATE)、删除(DELETE)或者插入(INSERT)操作时,MySQL会自动对这条记录加锁
间隙锁
当使用范围当条件进行修改时,会把范围中的符合条件的数据条数进行锁定,还会对一部分可能会修改的数据进行锁定,这部分就是间隙锁。
借鉴文章
MySQL常见优化策略_mysql优化策略-CSDN博客