内连接(INNER JOIN):
返回两张表中联结字段匹配的行。
左连接(LEFT JOIN):
返回左表所有的行,即使右表中没有匹配的行。
右连接(RIGHT JOIN):
返回右表所有的行,即使左表中没有匹配的行。
全外连接(FULL OUTER JOIN):
返回两张表中的所有行,左右表没有匹配的行时,结果为NULL。
SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.id
SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.id
SELECT * FROM table1 RIGHT JOIN table2 ON table1.id = table2.id
SELECT * FROM table1 FULL OUTER JOIN table2 ON table1.id = table2.id
对于MySQL中大表的查询优化,可以从以下几个方面进行:
综合运用以上手段可以大幅优化MySQL大表查询。
MySQL中的最左匹配原则(Leftmost Prefix Principle)指的是:
当查询条件使用了联合索引的最左前缀列作为条件时,索引才能被查询使用。
例如存在索引 (col1, col2, col3):
最左匹配原则的原因是MySQL索引结构是B+树,B+树叶子节点存储数据指针。
对索引的搜索都从树根开始,逐级搜索直至叶子节点,叶子节点数据顺序与索引顺序一致。
所以最左列确定后,叶子节点范围也确定,可以高效查找,否则无法利用已排序的叶子节点。
这决定了MySQL的索引需要按最频繁作为条件的列作为最左前缀列,以满足最左匹配原则,使索引生效。
在MySQL中,索引可能会出现失效的情况,常见的原因包括:
优点:
缺点:
数据库索引可以分以下几类:
1、单列索引
只针对一列建立的索引,一张表可以有多个单列索引。
2、唯一索引
索引列的值必须唯一,但允许有空值。
3、复合索引
基于多列建立的索引,只有使用了第一个字段才能生效。
4、前缀索引
只索引字段的前几个字符,提高查询效率。
5、全文索引(只有在MyISAM
引擎上才能使用)
针对文本的内容进行索引,用于全文搜索。
6、空间索引
MYSQL 5.7版本支持的空间数据索引。
7、哈希索引
将值进行哈希计算,然后索引哈希值,只支持精确等值查询。
8、主键索引
设计数据库索引的常见原则:
MySQL中的索引主要使用以下两种数据结构实现:
B+树
这是MySQL中最常见的索引结构,理由如下:
哈希表
InnoDB引擎支持哈希索引,原理是通过哈希函数计算索引键值的哈希值,然后映射到存储引擎页。
B+树比B树更适合实现数据库索引的原因有:
覆盖索引(Covering Index)指的是查询只通过访问索引就可以返回所需数据,而无需再次访问数据表,这可以大大提高查询效率。
是否覆盖索引的判断依据是:
形成覆盖索引的原因:
覆盖索引的优点:
主要原因如下:
磁盘IO是影响索引效率的主要因素。多路平衡查找树能减少磁盘IO次数。
数据库索引需要支持范围查找和顺序扫描,而非简单的点查找。B树可以高效支持区间查找。
数据库中的数据经常需要插入更新,B树对动态数据的支持更好。
B+树只在叶子节点存储数据,可以减少磁盘IO。
红黑树等平衡二叉树虽平衡,但磁盘IO次数较高。
数据库索引节点大小影响高速缓存效率。B树节点大小固定,有利于缓存。
B+树叶子节点链表支持高效地顺序访问索引。
所以数据库系统选择B树或B+树作为索引结构,主要是为了减少IO消耗,提高多用户高并发环境下的查询效率。
回表(Index Join Backward Scan) 是数据库系统优化器的一种执行计划。
当查询使用了覆盖索引,需要取得额外的列数据时,会触发回表机制:
根据索引条件,定位主键或唯一索引记录
拿到主键或唯一索引值
用该值到数据表中进行KEY Lookup,查看完整记录
获取需要的额外列数据
回表的优点是直接定位到所需记录,避免全表扫描。
回表的劣势是需要额外的JOIN操作,如果大批数据会增加开销。
是否回表由优化器决定,可以通过explain查看执行计划。
在索引设计时,使用覆盖索引可以有效减少回表情况。
事务的四大特性:
原子性(Atomicity):
事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
一致性(Consistency):
事务必须使数据库从一个一致性状态变换到另一个一致性状态。
隔离性(Isolation):
一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的。
持久性(Durability):
一旦事务完成,无论系统发生什么错误,其结果都不会受到影响,该事务的修改将会永久保存在数据库中。
综合起来,事务的这四大特性简称为ACID,指事务具备原子性、一致性、隔离性和持久性这四个特点。这能确保事务在高并发环境中数据的完整性和一致性。
脏读(Dirty read): 一个事务读取了另一个未提交事务修改的数据。
不可重复读(Nonrepeatable read): 一个事务多次读取同一数据,但读取结果不一致。
幻读(Phantom read):一个事务按相同查询条件重新读取数据,发现其他事务插入了新数据。
原因:
隔离级别越高,数据一致性就越好,但并发性越弱。 需要根据业务需求选择合适的隔离级别。 MySQL默认使用可重复读隔离级别,能避免常见的一致性问题。
查看隔离级别
select @@transaction_isolation;
设置隔离级别
set session transaction isolation level read uncommitted;
MySQL的事务在高并发下主要会遇到以下问题:
MySQL的事务会使用以下几种锁:
解决方案:
InnoDB 的几种锁的细节如下:
允许多个事务同时对记录进行读取操作。
其他事务只能再获得共享锁,不能获得排他锁。
只允许当前事务访问资源,其他事务不能访问。
保证事务隔离性,用于 update、delete 等修改操作。
事务在申请共享锁前需要获得的锁。
提升并发性, notified锁可以先获取IS锁。
在获取排他锁前需要获得的意向锁。
如果事务T1持有IX锁,其他事务只能获取IS锁,不能直接获取X锁,避免死锁。
对AUTO_INCREMENT类型的字段进行修改时,会加自动增长锁。
只允许一个事务进行自增操作,实现序列的唯一性。
对即将插入的数据行加插入意向锁,表示插入意图。
避免同一关键字的重复插入。
在不同的事务隔离级别下,InnoDB使用的锁机制有所不同:
只会对修改的行加排他锁,不会加任何读锁。
会出现脏读、不可重复读、幻读情况。
对读取的行加共享锁,对修改的行加排他锁。
可以防止脏读,但幻读、不可重复读可能发生。
对读取的行加共享锁,对修改的行加排他锁。
再加上间隙锁,可以防止幻读。
对读取查询范围加共享锁,对修改的行加排他锁。
加上间隙锁和Next-Key锁,完全串行化。
隔离级别越高,并发性越低,但数据一致性更好。需要根据业务需求折中考虑。
MySQL中可能出现死锁的典型情况:
两个事务以不同顺序请求锁资源,形成互相等待。
一个事务占用锁资源的同时,请求其他锁资源。
锁资源范围不明确,一个事务锁定范围过广。
锁粒度过细,事务在同一资源的不同数据行申请锁。
事务在锁资源时进行了DML操作。
解决死锁的方法:
尽量减少锁粒度,避免不必要的锁定资源范围。
避免事务中的锁竞争,按固定顺序或锁分段申请。
降低隔离级别,使用乐观锁等手段。
设置锁超时,防止无限等待。
死锁检测机制,事务回滚重试。
合理设计 schema,减少锁冲突。
根据业务分离操作集中在一个事务中,分段提交。
悲观锁和乐观锁是两种不同的并发控制方法:
悲观锁:
假设会发生并发冲突,屏蔽一切可能违反数据完整性的操作。
主要方式是通过数据库的锁机制控制并发访问。
线程在访问数据时需要先获得锁,操作完成后释放锁。
乐观锁:
假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。
主要方式是通过版本控制实现并发控制。
不对数据加锁,但在更新时检查版本是否发生变化。
更新失败时,重试更新操作。
相比之下,乐观锁适合高并发低冲突情况,不需要锁的开销,提高了吞吐量。
悲观锁和乐观锁的实现方式:
悲观锁:
使用 synchronized 或者 lock 进行锁定;
读取数据时上锁,更新完成后释放锁;
线程等待锁释放,可能造成线程阻塞。
乐观锁:
在数据表中新增版本号version字段;
更新时检查版本号是否变化,如果没变化则更新,否则重试。
不需要锁定资源,通过 retrying 来确保一致性。
具体实现:
悲观锁通过语言原生的lock来控制;
乐观锁在应用级别实现,在数据字段中加入版本来控制。
数据库的悲观锁通过锁机制实现。
MVCC则是一种优化的乐观锁理念。
MySQL常见的存储引擎包括:
MyISAM:
InnoDB:
Memory:
Archive:
各引擎有自己的优势场景,MyISAM适合干净快速读写,InnoDB带事务支持;Memory用于临时表,Archive用于归档存储。
InnoDB存储引擎的内存结构主要包含以下4大组件:
Buffer Pool
缓冲池,用于缓存数据和索引,避免频繁访问磁盘。它占用了InnoDB内存的大部分。
Log Buffer
红日志缓冲区,用于临时缓冲日志数据,提高写性能。
Lock System
锁管理系统,存储锁信息,管理事务并发控制。
Change Buffer
变更缓冲区,用于暂时记录对二级索引的变更,提高写入速度。
这4个组件各司其职,共同提高InnoDB的并发性能:
它们保证了InnoDB的事务支持与高性能。
MySQL InnoDB存储引擎通过MVCC(多版本并发控制)来支持事务并实现隔离级别,其基本原理是:
更新时,不直接覆盖旧记录,而是生成一个新的版本。
读取时,判断事务id和当前事务id,如果版本不可见,就通过回滚指针找到旧版本。
提交时将旧版本放入回收链表中待清理。
通过undo日志进行回滚恢复。
间隙锁和next-key锁实现对间隙和幻读的控制。
MVCC实现了非阻塞的读写和版本控制,支持事务隔离。但也带来了额外的开销和复杂度。
MySQL InnoDB中的快照读和当前读:
快照读(Snapshot read):
事务开始时创建快照,记录当前数据集状态。
事务读取时直接从快照读取数据,不用加锁。
实现非阻塞读,提高并发性。
当前读(Current read):
每次读取时直接从磁盘读取最新committed版本的数据。
需要加共享锁,可能造成阻塞。
可避免不可重复读的问题。
区别:
快照读通过一致的快照实现了非阻塞读。
当前读每次都读取最新数据,但有锁开销。
InnoDB默认是Repeatable Read隔离级别,使用快照读保证一致性且不阻塞读。
设计一个框架,实现MySQL表数据自动同步到Redis的步骤:
这样通过抽象框架进行封装,可以实现 MySQL 到 Redis 的自动化高效同步。
还可以读MySQL的binlog
MySQL的binlog二进制日志文件可以被读取和解析,常见的读取和解析binlog的方式有:
使用mysqlbinlog工具,它可以打印出binlog中的SQL语句,用于查看binlog。
例如:
mysqlbinlog mysql-bin.000001
在MySQL客户端使用SHOW BINLOG EVENTS,可以查看binlog中的事件。
使用mysql库提供的mysql_binlog_dump()函数读取binlog内容。
使用Binlog API,在代码中注册事件监听器,可以解析binlog事件。
使用第三方工具,如go-mysql-replication,用于复制和解析binlog。
读取binlog的常见应用场景:
将Redis中的数据同步到MySQL数据库中,通常有以下几种实现方式:
使用Redis自带的Keyspace Notifications功能,监听Redis键空间事件,通过触发器同步到MySQL。
编写程序定期扫描Redis,同步新增或更新的键值到MySQL对应表中。
使用Redis流水线(pipelining)批量获取数据,然后同步到MySQL中。
通过Redis Pub/Sub实现消息队列,由消费者程序获取消息并写入MySQL。
使用第三方同步中间件,如Canal等,解析Redis的数据变更同步到MySQL。
利用ElasticSearch作为中间层,使用Logstash从Redis中获取数据导入ES,再同步到MySQL。
使用共享存储的方式,使Redis和MySQL访问同一份数据文件或备份文件。
根据业务需求和系统架构,选择合适的同步方案来保证Redis和MySQL数据的一致性。
要解决MySQL和Redis之间数据一致性问题,主要的方法包括:
单向同步:只要保证MySQL到Redis或者Redis到MySQL的单向同步即可。
强制顺序:对数据操作进行强制顺序化,确保同步的顺序性。
避免循环更新:避免同时对两个数据源进行更新从而形成循环,通过去重等手段避免。
事务一致性:使用分布式事务来确保跨数据库的事务一致性。
事件溯源:通过事件溯源的方式确保数据库始终基于同一系列事件进行更新。
数据校对:定期进行数据校对,纠正不一致情况。
冲突解决策略:设定数据不一致时的冲突解决方案,如时间戳判断。
唯一键验证:使用唯一键验证来避免插入不一致的数据。
流处理保证:使用流处理链路严格保证一致性。
根据系统架构,选择合适的方案来满足一致性需求。
MySQL的常见架构可以分为以下几层:
连接层:支持各种客户端协议,包括基于TCP/IP的MySQL协议,ssh协议,内存socket等。
服务层:负责查询缓存,SQL解析、预处理、权限验证等功能。
引擎层:存储引擎层,对表进行存取和管理,支持InnoDB、MyISAM等多种存储引擎。
存储层:主要是文件系统和磁盘管理,存储引擎通过接口与之交互。
复制层:主从复制相关的日志管理、故障切换等功能。
连接池模块:管理缓冲客户端连接,提高连接性能。
优化器模块:Sql语句执行的查询优化、执行计划选择等。
监控数据库的常用方法和工具包括:
基于日志的监控:开启MySQL的slow log、error log等日志,并设置合理的参数,通过分析日志来监控数据库。
基于SNMP的监控:使用SNMP服务,通过查询状态参数来监控数据库。
使用AOM等数据库遥测框架:通过收集各类性能指标数据库进行监控。
系统性能统计:使用top、vmstat、iostat等系统命令查看数据库服务器的状态。
数据库的information_schema表:查询其中的metrics表可以获取数据库运行时指标。
使用Prometheus exporter等工具暴露数据库指标。
Grafana、Zabbix、Nagios等开源监控工具,提供数据库监控插件。
阿里云、腾讯云等云厂商的数据库监控服务。
根据需求选择合适的监控方法,可以更好地管理和优化数据库。
MySQL支持以下几种主从复制方式:
异步复制(Asynchronous Replication)
半同步复制(Semisynchronous Replication)
全同步复制(Synchronous Replication)
组复制(Group Replication)
MySQL 8.0的新复制方式,通过组内的协议实现多主多从。
可使每个节点成为读写节点。
延迟复制
延迟复制指的是从库可以配置在主库写入binlog日志一段时间后再应用日志中的修改。
实现方式是在从库配置delayed_replication_interval参数指定延迟时间。
使用场景:
延迟复制实现了在从库保留历史数据的功能,提供了一定的容错空间。
需要考虑延迟时间,监控从库复制进度,以免延迟过长影响使用。
数据库连接池是一种数据库资源复用技术,主要作用是提高数据库连接的使用效率。
具体来说,数据库连接池实现了以下功能:
缓存数据库连接对象,重用存在的连接,避免频繁创建销毁连接的资源开销。
管理连接对象数量,合理分配连接资源,避免无效连接占用资源。
管理空闲连接及其超时时间,释放超时空闲连接以节省资源。
提供连接使用数量监控,记录数据库连接的使用与性能情况。
提供线程安全的连接使用方式。
提供连接故障切换与重连机制,增强容错能力。
所以使用数据库连接池可以提高连接资源的利用率,节省连接创建和关闭的时间,降低系统开销,提高数据库访问性能和稳定性。
这是博主自己整理的MySQL面试题,有些是博主自己遇到过的面试题,如有错误,欢迎指正,如有不全的,欢迎提醒!!!