菜单

数据库

相关源文件

本文概述了JavaGuide存储库中涵盖的数据库技术。我们将探讨关系型数据库(主要是MySQL)和NoSQL数据库(主要是Redis),包括它们的基础、架构和关键概念。有关更具体的主题,例如详细的优化技术或高级数据库配置,请参阅相应的数据库特定页面。

关系型数据库概述

关系型数据库将数据存储在具有预定义架构的表中,数据以行和列的形式组织。它们通过主键和外键强制表之间的关系,确保数据的完整性。

来源: docs/database/mysql/mysql-questions-01.md

什么是关系型数据库?

关系型数据库建立在关系模型之上,该模型在存储的数据之间建立连接(一对一、一对多、多对多)。在关系型数据库中,数据存储在各种表中(例如用户表),其中每一行包含一个记录(例如一个用户的信息)。

大多数关系型数据库使用SQL(结构化查询语言)进行数据操作,并支持事务的ACID(原子性、一致性、隔离性、持久性)属性。

常见的关系型数据库系统包括MySQL、PostgreSQL、Oracle、SQL Server和SQLite(后者用于存储微信的本地聊天记录)。

来源: docs/database/mysql/mysql-questions-01.md:19-33

MySQL简介

MySQL是一个广泛使用的关系型数据库管理系统,主要用于应用程序数据的持久化存储,例如用户信息。由于其开源、免费和成熟的特性,MySQL在各种系统中得到了广泛应用。根据通用公共许可证(GPL)的规定,任何人都可以根据自己的需求下载和修改它。MySQL的默认端口是3306。

MySQL提供了几个优势:

  1. 成熟稳定,功能全面
  2. 开源免费
  3. 丰富的文档,包括详细的官方文档和高质量的文章
  4. 易于使用和维护
  5. 跨操作系统和编程语言的良好兼容性
  6. 活跃的社区和生态系统
  7. 卓越的事务支持,InnoDB的REPEATABLE-READ隔离级别
  8. 支持数据库分片、读写分离和高可用性

来源: docs/database/mysql/mysql-questions-01.md:50-72

MySQL 架构

MySQL遵循客户端-服务器架构,其中SQL查询经过多个处理阶段。下图展示了SQL语句在MySQL内的执行流程。

MySQL的核心架构包括:

  • 连接处理程序:处理连接到MySQL时的身份验证和权限。
  • 查询缓存:检查缓存结果(MySQL 8.0已移除)。
  • 解析器:分析SQL语法并验证语句的有效性。
  • 优化器:确定最有效的执行计划。
  • 执行器:在权限检查后执行语句。
  • 存储引擎:基于插件的架构,支持InnoDB、MyISAM、Memory等。

InnoDB是MySQL的默认存储引擎,对于大多数场景都是最佳选择。

来源: docs/database/mysql/mysql-questions-01.md:191-206

MySQL存储引擎

MySQL通过其插件架构支持多种存储引擎。您可以使用SHOW ENGINES命令查看所有支持的引擎。自5.5.5版本以来,InnoDB一直是MySQL的默认存储引擎。在此之前,MyISAM是默认引擎。

InnoDB与MyISAM

InnoDB和MyISAM之间的主要区别在于:

功能InnoDBMyISAM
行级锁定否,只有表级锁定
事务支持
外键支持
崩溃恢复
MVCC支持
索引实现数据文件即索引文件索引和数据文件是分开的
性能更适合读写混合环境更适合读密集型、简单查询

InnoDB使用缓冲池缓存数据和索引页,而MyISAM使用键缓存仅缓存索引页,不缓存数据页。

来源: docs/database/mysql/mysql-questions-01.md:208-351

MySQL数据类型

MySQL数据类型可大致分为三类:

  1. 数值类型:整数类型(TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT)、浮点类型(FLOAT、DOUBLE)、定点类型(DECIMAL)。
  2. 字符串类型:CHAR、VARCHAR、TINYTEXT、TEXT、MEDIUMTEXT、LONGTEXT、TINYBLOB、BLOB、MEDIUMBLOB、LONGBLOB。
  3. 日期和时间类型:YEAR、TIME、DATE、DATETIME、TIMESTAMP。

最常用的数据类型是:

类型存储范围用途
CHAR固定长度0-255个字符固定长度字符串,如密码
VARCHAR可变长度0-65,535个字符可变长度字符串,如姓名
TEXT可变长度最多65,535字节较长的文本,如文章
INT4 字节-2,147,483,648 到 2,147,483,647整数值
DECIMAL可变取决于精度精确的数值,如货币
DATETIME8 字节1000-01-01 00:00:00 到 9999-12-31 23:59:59日期和时间值

来源: docs/database/mysql/mysql-questions-01.md:73-189

数据类型的关键考虑因素

  • CHAR vs. VARCHAR:CHAR是固定长度,适用于长度相似的字符串。VARCHAR是可变长度,更适合长度可变的字符串。
  • DECIMAL vs. FLOAT/DOUBLE:DECIMAL可以存储精确的小数值,适用于金融数据,而FLOAT/DOUBLE存储近似值。
  • DATETIME vs. TIMESTAMP:DATETIME没有时区信息,而TIMESTAMP是时区感知的。TIMESTAMP使用更少的存储空间(4字节对8字节),但日期范围较小。
  • 避免使用TEXT和BLOB:这些类型存在一些限制,例如没有默认值、使用磁盘作为临时表、检索效率较低以及索引受限。

来源: docs/database/mysql/mysql-questions-01.md:97-154

MySQL索引

索引是一种用于快速数据检索和搜索的数据结构,本质上是一种排序的数据结构。索引通过减少需要扫描的数据量,显著提高了查询性能。

来源: docs/database/mysql/mysql-index.md:14-22, docs/database/mysql/mysql-index.md:137-165

索引数据结构

虽然哈希表、二叉搜索树和红黑树都可以用作索引结构,但MySQL主要在InnoDB和MyISAM存储引擎中都使用B+树进行索引。

为什么选择B+树?

  • 平衡树:无论数据分布如何,都能保持一致的搜索性能。
  • 多级结构:通过每个节点存储更多键来减少磁盘I/O。
  • 叶子节点连接:所有叶子节点都已链接,方便范围查询。
  • 数据存储:在InnoDB中,叶子节点存储实际数据(聚集索引)。

与擅长等值搜索但无法处理范围查询的哈希索引不同,B+树可以高效地同时支持等值和范围查询。

来源: docs/database/mysql/mysql-index.md:38-128

MySQL索引类型

MySQL支持多种索引类型:

  1. BTree索引:默认索引类型,实现为B+树。
  2. 哈希索引:用于等值比较,不适用于范围查询。
  3. 主键索引:行的唯一标识符,在InnoDB中是聚集索引。
  4. 唯一索引:确保列值唯一。
  5. 复合索引:基于多个列的索引。
  6. 覆盖索引:包含查询所需所有数据的索引。
  7. 全文索引:用于文本搜索。
  8. 前缀索引:基于字符串前几个字符的索引。
  9. 空间索引:用于地理数据类型。

来源: docs/database/mysql/mysql-index.md:137-165

InnoDB索引实现

InnoDB的索引实现方式与MyISAM不同:

  • 聚集索引:主键索引是聚集索引,意味着数据直接存储在B+树的叶子节点中。
  • 二级索引:非主键索引在叶子节点存储主键值,需要额外的查找才能访问行数据。
  • 索引选择:查询优化器根据基数、选择性和查询模式选择最有效的索引。

这种实现方式解释了为什么在InnoDB表中选择合适的主键很重要——主键会影响所有二级索引。

来源: docs/database/mysql/mysql-index.md:122-136, docs/database/mysql/mysql-questions-01.md:266-326

MySQL事务

事务是操作的逻辑单元,必须原子地执行——要么所有操作都成功,要么都不成功。经典的例子是银行转账,其中借记和贷记操作必须同时成功或失败。

来源: docs/database/mysql/mysql-questions-01.md:420-442

ACID 特性

MySQL的InnoDB引擎支持ACID属性:

  1. 原子性:事务是全有或全无的操作。
  2. 一致性:事务前后数据保持一致状态。
  3. 隔离性(Isolation):并发事务互不干扰
  4. 持久性:一旦提交,事务即使在系统故障期间也会持久化。

需要注意的是,原子性、隔离性和持久性是数据库的属性,而一致性是应用程序的属性,它可能依赖于数据库的属性。

来源: docs/database/mysql/mysql-questions-01.md:461-488

事务隔离级别

SQL标准定义了四种隔离级别来解决并发问题:

隔离级别脏读不可重复读幻读
READ UNCOMMITTED可能可能可能
READ COMMITTED避免可能可能
REPEATABLE READ避免避免可能*
SERIALIZABLE避免避免避免

*InnoDB对REPEATABLE READ的实现可以通过MVCC和Next-Key Locks来防止幻读。

MySQL的InnoDB默认隔离级别是REPEATABLE READ。

来源: docs/database/mysql/mysql-questions-01.md:490-592, docs/database/mysql/transaction-isolation-level.md

MySQL并发控制

MySQL使用两种主要机制进行并发控制:

  1. 锁定:一种悲观并发控制,使用读锁(共享)和写锁(排他)。
  2. MVCC(多版本并发控制):一种乐观方法,读者不阻塞写者,写者也不阻塞读者。

MVCC通过维护数据的多个版本,并根据事务时间戳和隔离级别确定哪些版本对事务可见来工作。

来源: docs/database/mysql/mysql-questions-01.md:534-553

NoSQL数据库:Redis

Redis(REmote DIctionary Server)是一个开源的、BSD许可的NoSQL数据库,用C语言编写。与传统数据库不同,Redis将数据存储在内存中(可选择持久化),提供极快的读写操作。它被广泛用作分布式缓存。

来源: docs/database/redis/redis-questions-01.md:19-27

为什么Redis如此之快?

Redis的卓越性能得益于:

  1. 内存操作:所有数据操作都在内存中进行,访问速度达到纳秒级别,而磁盘访问是毫秒级别。
  2. 高效I/O模型:Redis使用单线程事件循环和I/O多路复用,可以在没有上下文切换或锁争用的情况下并发处理多个连接。
  3. 优化的数据结构:Redis实现了高度优化的内部编码,如ziplist、quicklist、skiplist和hashtable。
  4. 简单协议:Redis使用RESP(Redis Serialization Protocol),该协议易于实现,解析效率高,并且是二进制安全的。

来源: docs/database/redis/redis-questions-01.md:36-48

Redis数据结构

Redis支持多种数据结构,每种数据结构都针对特定用例进行了优化:

  1. String:二进制安全的字符串,值最大为512MB。
  2. Hash:键值对集合,非常适合表示对象。
  3. List:字符串的链表,适用于队列和栈。
  4. Set:无序的唯一字符串集合。
  5. Sorted Set:按分数排序的集合,非常适合排名系统。
  6. Bitmap:字符串操作,允许进行位级别操作。
  7. HyperLogLog:用于计数唯一元素的概率性数据结构。
  8. Geospatial:存储和查询地理坐标。
  9. Stream:模拟日志数据结构的追加型集合。

每种数据结构都有专门的命令用于高效的操纵和检索。

来源: docs/database/redis/redis-questions-01.md:313-383, docs/database/redis/redis-data-structures-01.md

Redis的应用(除了缓存之外)

虽然Redis主要用作缓存,但它还有其他几种应用:

  1. 分布式锁:Redis可以高效地实现分布式锁,通常使用Redisson库。
  2. 限流:通过Redis+Lua脚本实现,或使用Redisson的RRateLimiter。
  3. 消息队列:Redis List或Stream可以充当消息代理。
  4. 延迟队列:Redisson提供了内置的延迟队列功能。
  5. 分布式会话:使用String或Hash类型存储可在服务器之间共享的会话数据。
  6. 复杂场景:Bitmap用于活跃用户跟踪,Sorted Set用于排行榜,HyperLogLog用于唯一访客计数。

来源: docs/database/redis/redis-questions-01.md:152-161

Redis作为消息队列

虽然Redis可以实现消息队列,但与专用消息中间件相比,它存在一些限制:

  • 基于List的实现:简单但缺乏广播能力和消息确认。
  • Pub/Sub系统:支持广播,但不持久化消息。
  • Stream数据类型:Redis 5.0中添加,支持消费者组、持久化和消息确认。

对于严肃的消息队列需求,建议使用RocketMQ或Kafka等专用解决方案,而不是Redis。

来源: docs/database/redis/redis-questions-01.md:166-262

Redis事务

Redis事务允许将多个命令捆绑在一起,按顺序执行,而不被中断。然而,Redis事务与传统数据库事务有很大不同:

  • 它们不支持回滚。
  • 在命令出错的情况下,它们不满足原子性。
  • 命令是顺序执行的,而不是全部一次性执行。
  • 每个命令仍需要网络交互。

Redis事务使用MULTI开始事务,然后是排队的命令,最后是EXEC执行所有命令。您可以使用WATCH进行乐观锁定,使用DISCARD取消事务。

来源: docs/database/redis/redis-questions-02.md:19-91

数据库选择指南

在选择不同的数据库技术时,请考虑以下因素:

关系型 vs. NoSQL

  • 关系型数据库在以下方面表现出色:

    • 结构化数据和固定模式。
    • 涉及多个表的复杂查询。
    • 需要ACID属性的事务。
    • 数据完整性约束。
  • Redis在以下方面表现出色:

    • 高速键值存储。
    • 缓存频繁访问的数据。
    • 实时分析
    • 实现分布式原语(锁、计数器)。
    • 低延迟操作。

何时将Redis与MySQL一起使用

一种常见的模式是同时使用MySQL和Redis。

  1. 将MySQL用作持久化、关系型数据的主要数据存储。
  2. 将Redis用作缓存层,以减轻MySQL的负载。
  3. 实现写穿透或写回缓存策略。
  4. 使用Redis来实现MySQL无法满足的功能,例如限流或实时排行榜。

来源: docs/database/redis/redis-questions-01.md:97-161

数据库优化技术

MySQL优化

MySQL优化涉及几个关键领域:

  1. 模式设计:

    • 使用适当的数据类型。
    • 进行范式化以减少冗余。
    • 考虑反范式化以应对读密集型工作负载。
  2. 索引策略:

    • 在经常查询的列上创建索引。
    • 使用覆盖索引进行读密集型操作。
    • 避免过度索引,这会降低写入速度。
  3. 查询优化:

    • 使用EXPLAIN分析查询执行计划。
    • 优化JOIN操作。
    • 限制结果集。
  4. 服务器配置:

    • 调整缓冲池大小。
    • 妥善配置查询缓存。
    • 优化连接处理。

来源: docs/database/mysql/mysql-high-performance-optimization-specification-recommendations.md

Redis优化

Redis优化侧重于:

  1. 内存管理:

    • 使用适当的数据结构。
    • 为键设置TTL(生存时间)。
    • 监控内存使用
  2. 连接管理:

    • 使用连接池。
    • 考虑使用流水线(pipelining)进行批量操作。
  3. 数据结构选择:

    • 为特定用例选择合适的数据结构。
    • 使用专门的命令进行原子操作。
  4. 持久化配置:

    • 在持久化需求和性能之间取得平衡。
    • 根据持久性要求配置RDB和AOF。

来源: docs/database/redis/redis-questions-02.md

结论

MySQL等关系型数据库和Redis等NoSQL数据库在现代应用程序架构中都扮演着重要角色。MySQL为具有复杂关系和结构化数据提供了强大的存储,而Redis则在高速操作、缓存和专用数据结构方面表现出色。

了解每种技术的优点和局限性,可以实现有效的数据库选择和使用模式。许多应用程序可以从混合方法中受益,使用MySQL进行持久化存储,使用Redis进行缓存和专用功能。