InnoDB和MyISAM的比较
事务支持:
- InnoDB支持:支持事务 (ACID 属性)。支持 Commit、Rollback 和 Savepoint 操作。适合需要事务处理的应用,例如银行系统。
- MyISAM:不支持事务。每次操作都是自动提交,不能回滚或中止。适合对事务要求不高的应用,例如简单的读写操作。
锁机制:
- InnoDB:支持行级锁(Row-Level Locking),并发性能更好。通过多版本并发控制(MVCC)实现高效的并发读写。适合高并发写入场景。
- MyISAM:只支持表级锁(Table-Level Locking),并发性能较低。插入或更新操作会锁住整个表,导致其他线程无法访问表。
外键:
- InnoDB:支持外键约束,能维护表间数据的一致性。在定义表时,可以指定 ON DELETE 和 ON UPDATE 操作。
- MyISAM:不支持外键约束。表间的引用完整性需要通过应用逻辑自行维护。
崩溃恢复:
- InnoDB:具备崩溃恢复能力。使用事务日志(Redo Log)和双写缓冲(Doublewrite Buffer)技术,在崩溃时可以恢复数据。适合关键数据场景。
- MyISAM:崩溃后可能会丢失数据或导致表损坏。提供 myisamchk 工具用于表修复,但不如 InnoDB 的自动恢复机制可靠。
性能比较:
- InnoDB:在写密集型、需要事务支持和高并发的场景下表现更优。由于支持事务和行级锁,写操作的开销较高。数据检索可能稍慢,但适合频繁的更新操作。
- MyISAM:读操作性能通常优于 InnoDB,适合读多写少的场景。因为不支持事务和行级锁,插入和查询开销较低。不适合频繁写入或需要高并发写的场景。
数据存储结构:
- InnoDB:聚簇索引(Clustered Index),主键索引和数据存储在同一个结构中。数据按主键顺序存储,非主键索引存储主键值的引用。更适合主键查询和范围查询。
- MyISAM:使用非聚簇索引,索引和数据分开存储。索引指向数据的物理位置。更适合频繁的全表扫描。
存储空间:
- InnoDB:占用更多的磁盘空间,因为需要维护事务日志和外键约束。表和索引数据存储在一个共享表空间或单独的 .ibd 文件中。
- MyISAM:相对较小的存储空间。表存储在 .MYD 和 .MYI 文件中,索引和数据分开管理。
全文索引:
- InnoDB:从 MySQL 5.6 开始支持全文索引,但性能一般。
- MyISAM:原生支持全文索引,适合需要全文检索的场景(如搜索引擎)。
应用场景:
- InnoDB:适用于需要事务支持、高并发写入和数据一致性的重要系统。例如:电子商务、银行、财务管理等。
- MyISAM:适用于读操作多、写操作少且对事务要求不高的系统。例如:日志系统、数据分析、简单内容管理系统等。
如果你的应用需要事务支持、数据一致性和高并发,选择 InnoDB。如果你的应用主要是读操作、不需要事务且需要较高的查询性能,选择 MyISAM。随着 MySQL 的发展,InnoDB 已经成为默认的存储引擎,未来的开发中推荐优先使用 InnoDB。
水平切分和垂直切分
水平切分: 水平切分是将数据按行划分到不同的数据库表或实例中,每个分片(shard)包含完整的列结构,但存储不同的数据行。
- 每个分片的数据结构相同(包含所有列)。
- 适合数据量大、查询操作以行为单位的场景。
- 常用于分表或分库。
优点:
- 分散压力:将数据分散到多个存储节点,减小单节点的存储和查询压力。
- 可扩展性强:数据增长时,只需增加新的分片。
- 高性能:适合对单行数据的查询和更新操作。
缺点:
- 跨分片查询复杂:需要额外的逻辑协调多个分片的查询结果。
- 分片策略设计难度大:需要选择合适的分片键。
- 数据迁移:当分片策略调整时,需要重新分布数据。
使用场景:
- 大型互联网系统,数据量巨大(如社交网络、电子商务)。
- 以用户 ID、订单 ID 等为主键进行查询的场景。
垂直切分:将数据库表按列划分,每个分片(shard)存储不同的列,以减少单表的列数或将功能模块拆分到不同的数据库中。
- 每个分片包含不同的列,按功能模块划分。
- 适合表结构复杂、列数较多或模块化设计的场景。
优点:
- 优化性能:减少单表的列数,提高缓存命中率。
- 模块化管理:不同模块的表可以存储在不同的数据库中,方便管理。
- 更高的并发性:不同模块的数据可分散到不同的服务器上,提高并发处理能力。
缺点:
- 查询复杂度增加:需要多表联合查询时性能下降。
- 耦合性高:切分后可能需要在应用层处理表间关联逻辑。
- 扩展性有限:当数据量持续增长时,仍需要进一步进行水平切分。
使用场景:
- 数据库中存在宽表(列数非常多)的情况。
- 系统需要根据业务模块划分(如用户模块、订单模块、支付模块)。
- 适合中小型数据库优化,避免数据表过宽导致性能下降。
注意事项:
很多人对水平切分存在误解,以为水平切分出来的数据表必须保存在不同的MySQL节点上。其实水平切分出来的数据表也可以保存在一个MySQL节点上面。不是水平切分一定需要多个MySQL节点。为什么这么说呢?
MySQL自带一种数据分区的技术,可以把一张表的数据,按照特殊规则,切分存储在不同的目录下。如果我们给Linux主机挂载了多块硬盘,我们完全可以利用MySQL分区技术,把一张表的数据切分存储在多个硬盘上。这样就由原来一块硬盘有限的IO能力,升级成了多个磁盘增强型的IO。
主从复制中涉及的三个线程
主从复制(Master-Slave Replication) 是数据库的一种数据复制机制,用于在主数据库(Master)和从数据库(Slave)之间同步数据。主数据库负责处理写操作,从数据库负责处理读操作。它能够提高数据的可用性、扩展读性能并提供数据备份的能力。
Binlog Thread(主库上的线程):
- 从库连接主库后,主库为这个连接分配一个 Binlog线程。
- 将更新写入二进制文件,并维护文件的一个索引来跟踪日志循环
I/O Thread(从库上的线程):
- 从库通过
CHANGE MASTER TO
命令指定主库的地址和同步信息,然后启动 I/O 线程。 - I/O 线程与主库的 Binlog Dump 线程建立连接。
- 它从主库接收二进制日志并存储到从库的中继日志(relay log)中。
SQL Thread(从库上的线程) :
- SQL 线程从中继日志中按顺序读取事务。
- 它依次在从库中执行这些事务,保证从库的数据与主库保持一致。
会产生的问题:
- 网络延迟:I/O 线程和 Binlog Dump 线程之间的通信速度可能会影响同步延迟。
- 事务一致性:如果 SQL 线程执行速度不够快,中继日志可能堆积,导致从库落后主库。
- 并行复制:在高负载场景下,可以使用多线程复制(如 MySQL 的并行复制功能)提高性能。
主从同步的延迟产生和解决方法
主从复制延迟(Replication Lag)指的是从库的数据落后于主库的时间差。这种延迟会影响读取一致性、数据实时性,甚至在某些业务场景下可能引起错误。
主从复制延迟产生原因:
- 主库写入负载过高:主库在短时间内写入大量数据,生成二进制日志(Binlog)的速度很快,而从库的处理速度跟不上,导致积压。
- 网络传输瓶颈:主库的 Binlog Dump 线程将日志传送给从库时,网络延迟、带宽不足或丢包问题会拖慢日志传输速度。
- 从库 I/O 线程瓶颈:从库的 I/O 线程负责从主库拉取日志,如果网络或系统 I/O 性能较差,会导致日志拉取不及时,进而引发延迟。
- 从库 SQL 线程处理能力不足:从库 SQL 线程需要依次读取中继日志(Relay Log)并执行日志中的事务。如果从库硬件性能较低(如 CPU、内存、磁盘 I/O)或存在锁争用,从库执行事务的速度会明显低于主库写入速度。
- 单线程复制限制:传统 MySQL 复制模式下,从库的 SQL 线程是单线程执行的,在处理大量事务或长事务时,容易形成瓶颈。
- 大事务或长事务:大事务或一次性提交大量更新的数据,日志量大且事务执行时间长,会拖慢从库的执行进程。
解决办法:
- 升级硬件
- 合理配置系统参数
- 改善网络环境
- 调整 Binlog 刷新策略(主库上可以调整
sync_binlog
参数,在保证数据安全的前提下适当提高日志同步效率。) - 采用并行复制(MySQL 5.7 及以上版本支持并行复制,从库可以配置多个并行工作线程(通过
slave_parallel_workers
参数),从而利用多核 CPU 并行执行事务。注意:并行复制通常需要在事务之间独立(如基于数据库或基于事务组的复制模式),如果事务间存在依赖,可能无法并行。) - 专用只读从库(将从库专用于只读查询,避免在从库上执行写操作或其他重负载任务,确保 SQL 线程资源充足。)
- 读写分离策略(在应用层面配置读写分离,使得对数据一致性要求不高的查询请求直接访问从库,从而减少主从复制的负担。)