开发转兼职DBA(六):换了个数据库,问题还是那些问题

开发转兼职DBA(六):换了个数据库,问题还是那些问题

前五篇讲的几乎都是Oracle。但如果你理解了底层原理,换到MySQL、PostgreSQL、SQL Server------问题变了外衣,骨架还是那个骨架。这篇做一个跨数据库的对照,看看哪些知识是"一次学会,到处使用"的。


文章目录

系列回顾

  1. 只会写SQL的那几年------DML/DDL,能跑就行
  2. 执行计划教我做事------全表扫描、索引、复合索引、统计信息
  3. 数据库起不来了------WAL、redo日志、事务持久性
  4. 又起不来了------MVCC、undo、事务隔离、并发控制
  5. 从救火到防火------参数、内存、监控、备份
  6. 换了个数据库,问题还是那些问题(本篇)

一、WAL------所有数据库都这么干

Oracle

复制代码
用户修改数据
    ↓
生成redo记录 → 写入Log Buffer → 提交时刷到redo log文件
    ↓
后台进程把脏块写到数据文件

Oracle的redo log是循环使用的,默认三组。可以配置归档模式(ARCHIVELOG),日志切换时自动归档,支持时间点恢复。

MySQL (InnoDB)

复制代码
用户修改数据
    ↓
生成redo记录 → 写入redo log buffer → 提交时刷到ib_logfile0/ib_logfile1
    ↓
后台线程把脏页写到.ibd数据文件

InnoDB的redo log也是循环使用,两个文件(ib_logfile0ib_logfile1)。MySQL还有binlog------用于主从复制和时间点恢复,和redo log是两套独立的日志。

sql 复制代码
-- MySQL查看redo log状态
SHOW ENGINE INNODB STATUS;

-- binlog相关
SHOW BINARY LOGS;
SHOW BINLOG EVENTS IN 'mysql-bin.000001';

PostgreSQL

PostgreSQL的WAL文件就叫WAL,不叫redo log。存放在pg_wal/目录下。

sql 复制代码
-- 查看WAL配置
SHOW wal_level;
SHOW max_wal_size;
SHOW checkpoint_completion_target;

PostgreSQL的WAL还有一个独特用途:逻辑复制和CDC(Change Data Capture)。通过解析WAL,可以实时捕获数据变更。

SQL Server

SQL Server叫Transaction Log,每个数据库有自己的日志文件(.ldf)。

sql 复制代码
-- 查看事务日志
DBCC SQLPERF(LOGSPACE);

-- 查看日志恢复模式
SELECT name, recovery_model_desc FROM sys.databases;

对照

数据库 叫什么 文件 循环使用 归档支持
Oracle Redo Log redo01.log, redo02.log, redo03.log ARCHIVELOG模式
MySQL Redo Log + Binlog ib_logfile0, ib_logfile1 binlog持久化
PostgreSQL WAL pg_wal/下的分段文件 WAL归档
SQL Server Transaction Log database_name.ldf 是(日志截断后) 完整恢复模式

核心原理一样:先写日志,再写数据。日志落盘 = 事务持久化。崩溃后用日志重做。


二、MVCC------实现不同,目标一样

Oracle

MVCC通过undo段实现。数据块里只有最新版本,旧版本在undo段里。

复制代码
数据块:id=1, xm='李四'(事务A修改后的值)
undo段:id=1, xm='张三'(事务A修改前的值)

事务B读取时,如果B的SCN早于A的修改,去undo段里找旧值。

MySQL (InnoDB)

MVCC通过undo log实现。和Oracle类似,旧版本存在undo log里。

InnoDB每行数据有两个隐藏列:

  • DB_TRX_ID:最后修改这行的事务ID
  • DB_ROLL_PTR:指向undo log的回滚指针

读取时,根据当前事务的"读视图"(Read View)判断哪行对自己可见。如果最新版本不可见,沿着DB_ROLL_PTR找到旧版本。

PostgreSQL

MVCC的实现方式不一样------旧版本和新版本直接存在同一个表里

每行数据有:

  • xmin:插入这行的事务ID
  • xmax:删除这行的事务ID(0表示未被删除)
  • 更新 = 删除旧行 + 插入新行

读取时,判断xminxmax是否在当前事务的可见范围内。

代价:表容易膨胀。旧版本留在表里,需要VACUUM清理。

sql 复制代码
-- PostgreSQL查看表的膨胀情况
SELECT schemaname, relname, n_dead_tup, n_live_tup
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC;

对照

数据库 旧版本存在哪 读取时怎么判断 表膨胀问题
Oracle undo段 SCN比较
MySQL undo log Read View + DB_TRX_ID
PostgreSQL 数据表本身 xmin/xmax比较 有,需要VACUUM
SQL Server tempdb 行版本存储 tempdb空间增长

核心原理一样:写不阻塞读,读不阻塞写。每个事务看到一致性快照。


三、事务隔离级别

SQL标准定义了四个隔离级别,各数据库的实现有差异:

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

各数据库的默认隔离级别

数据库 默认隔离级别 实现方式
Oracle READ COMMITTED MVCC + undo
MySQL (InnoDB) REPEATABLE READ MVCC + Next-Key Lock(间隙锁,防止幻读)
PostgreSQL READ COMMITTED MVCC + xmin/xmax
SQL Server READ COMMITTED 默认用锁,可开启MVCC(RCSI)

MySQL的特殊之处

MySQL默认REPEATABLE READ,而且在InnoDB的实现中,通过**间隙锁(Gap Lock)**防止幻读------比SQL标准的REPEATABLE READ更强。

sql 复制代码
-- MySQL查看隔离级别
SELECT @@transaction_isolation;

-- 设置隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

Oracle的特殊之处

Oracle不支持READ UNCOMMITTED和REPEATABLE READ。只有READ COMMITTED和SERIALIZABLE两种。READ COMMITTED是默认的------每条SQL执行时获取新的一致性快照。

sql 复制代码
-- Oracle设置隔离级别
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

Oracle的SERIALIZABLE不是真的串行执行------而是事务开始时获取一个SCN,后续所有读操作都看到这个SCN时刻的数据快照。如果事务尝试修改已经被其他事务修改的数据,报ORA-08177: can't serialize access for this transaction


四、索引------B+树是标配

各数据库的索引类型

数据库 主索引 B+树 Hash 全文 其他
Oracle B+树 有(内存列) 有(CTXSYS) 位图索引、函数索引
MySQL (InnoDB) 聚簇索引(B+树) 有(MEMORY引擎) 有(FULLTEXT) 空间索引(R-Tree)
PostgreSQL 堆表 有(GIN/GIST) BRIN、SP-GiST
SQL Server 聚簇索引(B+树) 无内置 有(全文搜索) 列存储索引、XML索引

MySQL的聚簇索引

MySQL InnoDB的主键索引是聚簇索引 ------数据文件本身就是按主键组织的B+树。二级索引的叶子节点存的是主键值,不是行号。

复制代码
聚簇索引(主键):
  叶子节点存完整行数据

二级索引(xm):
  叶子节点存 主键值 → 回聚簇索引查完整数据

这意味着:用二级索引查数据,要查两次索引(一次二级索引,一次聚簇索引)。如果查询只需要索引列和主键列,就不需要回表------索引覆盖。

Oracle的堆表

Oracle默认是堆表------数据没有特定顺序,存在哪由空间管理决定。索引的叶子节点存的是ROWID(物理行地址),可以直接定位到数据块。

复制代码
索引(xm):
  叶子节点存 ROWID → 直接到数据块取数据

Oracle的索引回表通常比MySQL快------ROWID直接指向物理位置,不需要再查一次索引。

查看执行计划

sql 复制代码
-- Oracle
EXPLAIN PLAN FOR SELECT * FROM t WHERE xm = '张三';
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

-- MySQL
EXPLAIN SELECT * FROM t WHERE xm = '张三';

-- PostgreSQL
EXPLAIN ANALYZE SELECT * FROM t WHERE xm = '张三';

-- SQL Server
SET SHOWPLAN_TEXT ON;
GO
SELECT * FROM t WHERE xm = '张三';
GO

五、备份恢复

各数据库的备份方式

数据库 物理备份工具 逻辑备份工具 在线备份
Oracle RMAN expdp/impdp ARCHIVELOG模式
MySQL mysqlbackup/xtrabackup mysqldump binlog + LVM快照
PostgreSQL pg_basebackup pg_dump/pg_restore WAL归档 + 复制槽
SQL Server SQL Server备份 BCP/SSIS 完整恢复模式

恢复到指定时间点

Oracle:

sql 复制代码
RMAN> RUN {
    SET UNTIL TIME "TO_DATE('2024-01-15 14:00:00', 'YYYY-MM-DD HH24:MI:SS')";
    RESTORE DATABASE;
    RECOVER DATABASE;
    ALTER DATABASE OPEN RESETLOGS;
}

MySQL:

bash 复制代码
mysqlbinlog --stop-datetime="2024-01-15 14:00:00" mysql-bin.000001 | mysql -u root -p

PostgreSQL:

复制代码
restore_command = 'cp /archive/%f %p'
recovery_target_time = '2024-01-15 14:00:00'

SQL Server:

sql 复制代码
RESTORE DATABASE mydb FROM DISK = 'backup.bak'
WITH STOPAT = '2024-01-15 14:00:00', RECOVERY;

做的事都一样:恢复全量备份 + 重放日志到指定时间点。


六、监控

各数据库的"慢查询"配置

Oracle: 自动采集(AWR),也可以手动追踪:

sql 复制代码
ALTER SYSTEM SET sql_trace=TRUE;

MySQL:

sql 复制代码
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 2;  -- 超过2秒记录

PostgreSQL:

sql 复制代码
ALTER SYSTEM SET log_min_duration_statement = 2000;  -- 超过2秒记录

SQL Server:

sql 复制代码
-- 扩展事件
CREATE EVENT SESSION [SlowQueries] ON SERVER
ADD EVENT sqlserver.rpc_completed(
    WHERE duration > 2000000);  -- 微秒

各数据库的"等待事件"

数据库 查等待事件 查慢SQL
Oracle v$system_event v$sql
MySQL performance_schema.events_waits_summary sys.statements_with_runtimes_in_95th_percentile
PostgreSQL pg_stat_activity pg_stat_statements
SQL Server sys.dm_os_wait_stats sys.dm_exec_query_stats

做的事都一样:查数据库时间花在哪了,查哪条SQL最慢,查谁在等谁。


七、一次学会,到处使用

把前五篇学的东西做一个跨数据库映射:

概念 Oracle MySQL PostgreSQL SQL Server
WAL Redo Log Redo Log + Binlog WAL Transaction Log
MVCC旧版本 undo段 undo log 数据表内 tempdb
默认隔离级别 READ COMMITTED REPEATABLE READ READ COMMITTED READ COMMITTED
执行计划 DBMS_XPLAN EXPLAIN EXPLAIN ANALYZE SHOWPLAN
索引结构 B+树 + ROWID B+树 + 聚簇索引 B+树 + CTID B+树 + 聚簇索引
物理备份 RMAN xtrabackup pg_basebackup BACKUP DATABASE
逻辑备份 expdp mysqldump pg_dump BCP
慢查询 AWR slow_query_log log_min_duration Extended Events
等待事件 v$system_event performance_schema pg_stat_activity dm_os_wait_stats

名字不同,做的事情一样。


总结:问题没变,只是解法换了名字

这个系列从DML/DDL讲到WAL、MVCC、事务隔离、索引、备份恢复、监控。所有内容以Oracle为主线,但每个概念在其他数据库里都有对应。

数据库换了,语言换了,架构换了。但核心问题------数据怎么不丢、并发怎么控制、查询怎么优化、出事怎么恢复------从Oracle到MySQL到PostgreSQL,一个都没变。

如果你在Oracle上理解了WAL、理解了MVCC、理解了执行计划、经历过崩溃恢复------换到MySQL,你的学习曲线不是从零开始,而是从"名字不一样"开始。原理你已经懂了,剩下的只是查手册。

这就是底层原理的价值------它是跨数据库的通用货币。


标签:#DBA #Oracle #MySQL #PostgreSQL #SQL Server #WAL #MVCC #跨数据库 #底层原理

相关推荐
handler013 小时前
【MySQL】常用约束语法总结
linux·运维·数据库·笔记·mysql
一条泥憨鱼3 小时前
详解MyBatis 动态 SQL
java·数据库·sql·mysql·mybatis·动态sql
weixin_3975740913 小时前
用自然语言查数据库出图表靠谱吗?一次智能问数实践复盘
数据库
字节跳动开源15 小时前
Viking AI 搜索 CLI 正式发布:会说话,就能做搜索推荐
数据库·人工智能·开源
TechWJ16 小时前
数据库在公司内网,出差路上想查数据怎么办?
服务器·数据库·mariadb
我是一颗柠檬16 小时前
【MySQL全面教学】MySQL事务与ACID Day9(2026年)
数据库·后端·mysql
橙子圆12316 小时前
Redis知识9之集群
数据库·redis·缓存
BlackHeart120316 小时前
【SQL】Oracle中序列(Sequence)作为默认值引发的ORA-00979
数据库·sql·oracle
bug菌17 小时前
【SpringBoot 3.x 第254节】夯爆了,数据库访问性能优化实战详解!
数据库·spring boot·后端