欢迎光临
我们一直在努力

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

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

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


文章目录

  • 开发转兼职DBA(六):换了个数据库,问题还是那些问题
    • 系列回顾
    • 一、WAL——所有数据库都这么干
      • Oracle
      • MySQL (InnoDB)
      • PostgreSQL
      • SQL Server
      • 对照
    • 二、MVCC——实现不同,目标一样
      • Oracle
      • MySQL (InnoDB)
      • PostgreSQL
      • 对照
    • 三、事务隔离级别
      • 各数据库的默认隔离级别
      • MySQL的特殊之处
      • Oracle的特殊之处
    • 四、索引——B+树是标配
      • 各数据库的索引类型
      • MySQL的聚簇索引
      • Oracle的堆表
      • 查看执行计划
    • 五、备份恢复
      • 各数据库的备份方式
      • 恢复到指定时间点
    • 六、监控
      • 各数据库的"慢查询"配置
      • 各数据库的"等待事件"
    • 七、一次学会,到处使用
    • 总结:问题没变,只是解法换了名字

系列回顾

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

  • 一、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_logfile0、ib_logfile1)。MySQL还有binlog——用于主从复制和时间点恢复,和redo log是两套独立的日志。

    — 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/目录下。

    — 查看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)。

    — 查看事务日志
    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表示未被删除)
    • 更新 = 删除旧行 + 插入新行

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

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

    — 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更强。

    — MySQL查看隔离级别
    SELECT @@transaction_isolation;

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

    Oracle的特殊之处

    Oracle不支持READ UNCOMMITTED和REPEATABLE READ。只有READ COMMITTED和SERIALIZABLE两种。READ COMMITTED是默认的——每条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直接指向物理位置,不需要再查一次索引。

    查看执行计划

    — 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:

    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:

    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:

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

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


    六、监控

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

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

    ALTER SYSTEM SET sql_trace=TRUE;

    MySQL:

    SET GLOBAL slow_query_log = ON;
    SET GLOBAL long_query_time = 2; — 超过2秒记录

    PostgreSQL:

    ALTER SYSTEM SET log_min_duration_statement = 2000; — 超过2秒记录

    SQL Server:

    — 扩展事件
    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最慢,查谁在等谁。


    七、一次学会,到处使用

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

    概念OracleMySQLPostgreSQLSQL 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 #跨数据库 #底层原理

    赞(0)
    未经允许不得转载:171主机测评 » 开发转兼职DBA(六):换了个数据库,问题还是那些问题
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址