iT邦幫忙

0

MySQL 与 Oracle 性能调优

  • 分享至 

  • xImage
  •  

适用场景:电商平台、网络游戏、高并发互联网系统

数据规模:百万级、千万级、亿级、百亿级

数据库:MySQL 8.0 / 8.4、Oracle 19c / 23ai

核心目标:提高 SQL 执行效率、提升并发能力、降低资源消耗、保证数据一致性与稳定性。


一、海量数据场景下的数据库性能问题

数据规模 电商场景 网游场景 主要问题
10万 小型商城订单 游戏角色数据 单库通常可以支撑
100万 商品、用户、订单 角色、装备、背包 SQL 和索引设计
1000万 订单明细 玩家交易流水 慢查询、索引膨胀
1亿 订单、支付流水 游戏行为日志 I/O、锁竞争、归档
10亿 多年历史订单 多区服交易日志 分区、冷热分离
100亿以上 大型电商平台 大型游戏集群 分布式架构、数据分层

注意:

数据量大不一定代表性能差。

数据库性能还取决于:

  1. QPS:每秒查询数量。
  2. TPS:每秒事务数量。
  3. 并发连接数。
  4. SQL 扫描的数据量。
  5. 索引命中情况。
  6. CPU 使用率。
  7. 内存使用率。
  8. 磁盘 I/O。
  9. 锁等待时间。
  10. 数据库架构。

例如:

  • 10亿条很少访问的历史日志,可能没有明显性能压力。
  • 1000万条频繁更新的订单数据,可能产生严重锁竞争。

二、数据库调优的整体思路

2.1 调优原则

数据库调优不能一开始就增加索引、扩大内存或者增加服务器。

正确思路:

发现性能问题
    ↓
收集性能指标
    ↓
确定瓶颈位置
    ↓
分析SQL执行计划
    ↓
制定优化方案
    ↓
测试环境验证
    ↓
灰度上线
    ↓
监控优化效果

核心原则:

先定位问题,再实施优化;先优化 SQL 和索引,再考虑数据库架构扩展。


2.2 数据库调优的六个层次

层次 优化内容 常见方案
第一层 SQL SQL 改写、减少扫描
第二层 索引 联合索引、覆盖索引
第三层 表结构 分区、归档、冷热分离
第四层 数据库实例 内存、Redo、连接池
第五层 系统架构 Redis、读写分离、分库分表
第六层 硬件 CPU、内存、SSD、网络

常见优化顺序:

SQL优化
   ↓
索引优化
   ↓
事务与锁优化
   ↓
表结构优化
   ↓
数据库参数优化
   ↓
缓存与读写分离
   ↓
分区、分库分表
   ↓
硬件扩容

注意:实际优化顺序应由监控结果决定。


三、MySQL 海量数据调优

3.1 MySQL 性能问题定位

3.1.1 查看数据库状态

SHOW GLOBAL STATUS LIKE 'Questions';

SHOW GLOBAL STATUS LIKE 'Threads_connected';

SHOW GLOBAL STATUS LIKE 'Threads_running';

SHOW GLOBAL STATUS LIKE 'Slow_queries';

SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%';

SHOW GLOBAL STATUS LIKE 'Innodb_row_lock%';

重点指标:

指标 作用
Threads_connected 当前连接数
Threads_running 活跃线程数
Slow_queries 累计慢查询数量
Innodb_buffer_pool_reads 物理读取次数
Innodb_row_lock_waits 行锁等待次数

注意:QPS、TPS 应通过两个采样时间点的计数器差值计算。


3.1.2 开启慢查询日志

SET GLOBAL slow_query_log = ON;

SET GLOBAL long_query_time = 1;

说明:

  • long_query_time=1 表示慢查询阈值为1秒。
  • SET GLOBAL 对已建立连接的会话级参数不一定立即生效。
  • 生产环境应根据业务延迟要求设置阈值。
  • 持久化配置可使用配置文件或适用版本的 SET PERSIST。

分析慢查询:

mysqldumpslow -s t -t 20 slow.log

也可以使用:

pt-query-digest slow.log

重点分析:

  1. SQL 执行次数。
  2. 平均执行时间。
  3. 最大执行时间。
  4. 扫描行数。
  5. 返回行数。
  6. SQL 执行频率。

3.1.3 查看正在执行的 SQL

SHOW FULL PROCESSLIST;

重点关注:

  • 长时间运行的 SQL。
  • 锁等待。
  • 大量活跃连接。
  • 长事务。
  • 大范围 UPDATE。
  • 大范围 DELETE。

MySQL 8.0 可以使用 Performance Schema:

SELECT
    DIGEST_TEXT,
    COUNT_STAR,
    ROUND(AVG_TIMER_WAIT / 1e12, 3) AS avg_seconds,
    ROUND(SUM_TIMER_WAIT / 1e12, 3) AS total_seconds,
    SUM_ROWS_EXAMINED,
    SUM_ROWS_SENT
FROM performance_schema.events_statements_summary_by_digest
WHERE DIGEST_TEXT IS NOT NULL
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 20;

作用:

找出累计消耗数据库时间最多的 SQL。


3.2 MySQL SQL 优化

案例一:电商订单查询优化

假设订单表有1亿条数据。

CREATE TABLE orders (
    id BIGINT PRIMARY KEY,
    user_id BIGINT NOT NULL,
    order_no VARCHAR(64) NOT NULL,
    status TINYINT NOT NULL,
    amount DECIMAL(12,2) NOT NULL,
    create_time DATETIME NOT NULL
) ENGINE=InnoDB;

原始 SQL:

SELECT *
FROM orders
WHERE user_id = 10001
ORDER BY create_time DESC
LIMIT 20;

问题:

  • 没有合适索引时,可能扫描大量数据。
  • 可能产生额外排序。
  • SELECT * 增加数据读取与传输。

优化:

CREATE INDEX idx_user_time_id
ON orders(user_id, create_time DESC, id DESC);

改写 SQL:

SELECT
    id,
    order_no,
    status,
    amount,
    create_time
FROM orders
WHERE user_id = 10001
ORDER BY create_time DESC, id DESC
LIMIT 20;

优化原理:

  1. 利用 user_id 定位订单。
  2. 利用索引顺序减少排序。
  3. 使用 id 保证稳定排序。
  4. 只返回必要字段。

验证:

EXPLAIN ANALYZE
SELECT
    id,
    order_no,
    status,
    amount,
    create_time
FROM orders
WHERE user_id = 10001
ORDER BY create_time DESC, id DESC
LIMIT 20;

重点观察:

  • 实际扫描行数。
  • 实际执行时间。
  • 是否使用索引。
  • 是否出现额外排序。

案例二:深分页优化

原始 SQL:

SELECT *
FROM orders
ORDER BY id
LIMIT 1000000, 20;

问题:

MySQL 可能需要扫描大量记录,再丢弃前面的数据。

优化:

SELECT *
FROM orders
WHERE id > 1000000
ORDER BY id
LIMIT 20;

注意:

这里的 1000000 必须是上一页最后一条记录的真实 ID,而不是分页偏移量。

这种方式称为:

游标分页 / Keyset Pagination

适用场景:

  • 电商订单列表。
  • 商品浏览记录。
  • 游戏交易流水。
  • 玩家操作日志。

缺点:

不适合直接随机跳转到任意页。


案例三:避免索引字段使用函数

原始 SQL:

SELECT *
FROM orders
WHERE DATE(create_time) = '2026-10-01';

问题:

对索引字段使用函数,可能导致普通索引无法被高效使用。

优化:

SELECT *
FROM orders
WHERE create_time >= '2026-10-01'
  AND create_time < '2026-10-02';

使用时间范围查询,通常更容易利用 B-Tree 索引。


案例四:避免 SELECT *

原始 SQL:

SELECT *
FROM player_inventory
WHERE player_id = 10001;

优化:

SELECT item_id, quantity
FROM player_inventory
WHERE player_id = 10001;

收益:

  • 减少网络传输。
  • 减少读取的数据。
  • 降低应用内存消耗。
  • 增加使用覆盖索引的机会。

3.3 MySQL 索引优化

3.3.1 联合索引

游戏装备表:

CREATE TABLE player_equipment (
    id BIGINT PRIMARY KEY,
    player_id BIGINT NOT NULL,
    equipment_type INT NOT NULL,
    quality INT NOT NULL,
    level INT NOT NULL
);

查询:

SELECT *
FROM player_equipment
WHERE player_id = 10001
  AND equipment_type = 2;

优化:

CREATE INDEX idx_player_type
ON player_equipment(player_id, equipment_type);

设计联合索引时需要考虑:

  1. 等值查询条件。
  2. 范围查询条件。
  3. 排序字段。
  4. 字段选择性。
  5. 查询频率。
  6. 索引维护成本。

不要机械地认为选择性最高的字段必须排在第一位。


3.3.2 覆盖索引

CREATE INDEX idx_player_type_quality
ON player_equipment(
    player_id,
    equipment_type,
    quality
);

查询:

SELECT quality
FROM player_equipment
WHERE player_id = 10001
  AND equipment_type = 2;

可能直接从索引获取结果,减少回表操作。

适用场景:

  • 高频查询。
  • 返回字段较少。
  • 查询条件稳定。

3.3.3 索引过多的问题

索引不是越多越好。

索引过多会导致:

  • INSERT 变慢。
  • UPDATE 变慢。
  • DELETE 变慢。
  • 占用更多磁盘。
  • 占用更多 Buffer Pool。
  • 增加 DDL 维护成本。

优化建议:

  • 删除确认无用的索引。
  • 合并重复索引。
  • 避免为每个字段单独建立索引。
  • 根据真实 SQL 访问模式设计索引。

3.4 MySQL InnoDB 参数优化

3.4.1 Buffer Pool

[mysqld]
innodb_buffer_pool_size=16G

作用:

缓存 InnoDB 数据页和索引页。

对于独占数据库服务器,常见起点为物理内存的50%~75%,部分环境可以更高。

例如:

32GB 内存的独占数据库服务器,可以先评估16GB~24GB范围。

实际配置需要预留:

  • 操作系统内存。
  • 连接内存。
  • 排序与临时表内存。
  • 监控与备份进程内存。

3.4.2 Redo Log

MySQL 8.0.30 及后续版本:

innodb_redo_log_capacity=4G

Redo Log 容量过小:

  • 可能导致频繁检查点。
  • 增加数据页刷盘压力。

Redo Log 容量过大:

  • 增加部分恢复和运维成本。

需要结合 Redo 生成速率、Checkpoint 压力和恢复时间要求调整。


3.4.3 事务持久性

innodb_flush_log_at_trx_commit=1
参数值 特点 风险
1 每次提交写入并刷盘 持久性保障较强
2 提交写入日志,通常周期性刷盘 系统崩溃可能丢失近期事务
0 通常周期性写入与刷盘 进程崩溃也可能丢失近期事务

对于:

  • 电商支付。
  • 订单交易。
  • 游戏金币。
  • 游戏装备交易。

通常优先使用:

innodb_flush_log_at_trx_commit=1
sync_binlog=1

还需要结合存储设备、复制和故障恢复机制保证整体可靠性。


3.5 MySQL 分区表

适用场景:

  • 电商历史订单。
  • 支付流水。
  • 游戏日志。
  • 玩家操作记录。

示例:

CREATE TABLE game_log (
    id BIGINT NOT NULL,
    player_id BIGINT NOT NULL,
    event_type INT NOT NULL,
    create_time DATETIME NOT NULL,
    PRIMARY KEY(id, create_time)
)
PARTITION BY RANGE COLUMNS(create_time) (
    PARTITION p202601 VALUES LESS THAN ('2026-02-01'),
    PARTITION p202602 VALUES LESS THAN ('2026-03-01'),
    PARTITION pmax VALUES LESS THAN (MAXVALUE)
);

注意:

MySQL 分区表的所有唯一键必须包含分区表达式涉及的列。

因此主键设计为:

PRIMARY KEY(id, create_time)

按时间查询:

SELECT *
FROM game_log
WHERE create_time >= '2026-02-01'
  AND create_time < '2026-03-01';

可以利用分区裁剪。

分区优点:

  1. 便于按时间管理数据。
  2. 减少符合分区条件的查询扫描范围。
  3. 方便归档和清理历史数据。
  4. 降低部分维护操作的复杂度。

注意:

分区不等于分库分表,也不意味着所有 SQL 都会变快。

生产环境需要定期维护分区,避免所有新数据长期进入 pmax。


3.6 MySQL 分库分表

当单实例吞吐量或存储容量成为明确瓶颈时,可以考虑水平拆分。

订单系统
    │
    ├── order_db_0
    │      ├── orders_00
    │      ├── orders_01
    │      └── orders_02
    │
    ├── order_db_1
    │      ├── orders_00
    │      ├── orders_01
    │      └── orders_02
    │
    └── order_db_2
           ├── orders_00
           ├── orders_01
           └── orders_02

简单路由示例:

int dbIndex = (int) (userId % 4);

int tableIndex = (int) (userId % 16);

注意:

简单取模在扩容时会产生大量数据重新映射的问题。

生产环境需要解决:

  1. 分片路由。
  2. 全局唯一 ID。
  3. 跨库 JOIN。
  4. 分布式事务。
  5. 跨分片分页。
  6. 数据迁移。
  7. 扩容与缩容。
  8. 数据一致性。
  9. 热点分片。
  10. 备份恢复。

常见方案:

  • Apache ShardingSphere。
  • Vitess。
  • 自研分片路由层。

四、Oracle 海量数据调优

4.1 Oracle 性能问题定位

4.1.1 查看活跃会话

SELECT
    sid,
    serial#,
    username,
    status,
    sql_id,
    event,
    wait_class,
    blocking_session
FROM v$session
WHERE status = 'ACTIVE'
  AND type = 'USER';

重点关注:

  • 活跃 SQL。
  • 等待事件。
  • 阻塞会话。
  • CPU 消耗。
  • I/O 等待。
  • 长事务。

4.1.2 查找高消耗 SQL

SELECT *
FROM (
    SELECT
        sql_id,
        executions,
        elapsed_time / 1000000 AS total_seconds,
        cpu_time / 1000000 AS cpu_seconds,
        buffer_gets,
        disk_reads
    FROM v$sql
    WHERE executions > 0
    ORDER BY elapsed_time DESC
)
WHERE ROWNUM <= 20;

重点分析:

  1. SQL 总耗时。
  2. SQL 执行次数。
  3. CPU 时间。
  4. 逻辑读取。
  5. 物理读取。
  6. 单次平均执行时间。

4.1.3 Oracle 常见诊断工具

工具 作用
AWR 历史性能分析
ASH 活跃会话分析
ADDM 自动性能诊断
SQL Monitor SQL 执行过程监控
DBMS_XPLAN 执行计划分析
Statspack 历史性能统计

注意:

AWR、ASH、ADDM 及部分 SQL Monitor 功能涉及 Oracle 额外授权要求,生产环境应核对许可证。


4.2 Oracle 执行计划分析

EXPLAIN PLAN FOR
SELECT *
FROM orders
WHERE user_id = 10001;

查看执行计划:

SELECT *
FROM TABLE(DBMS_XPLAN.DISPLAY);

查看真实游标执行计划:

SELECT *
FROM TABLE(
    DBMS_XPLAN.DISPLAY_CURSOR(
        NULL,
        NULL,
        'ALLSTATS LAST'
    )
);

注意:

ALLSTATS LAST 需要相关执行统计已被采集。

重点指标:

指标 含义
E-Rows 预计行数
A-Rows 实际行数
Buffers 逻辑读取
Reads 物理读取
Starts 执行次数
Operation 执行操作

如果:

E-Rows = 100

A-Rows = 1000000

说明优化器行数估算可能严重偏离实际情况。

需要检查:

  • 统计信息。
  • 数据倾斜。
  • SQL 关联条件。
  • 直方图。
  • 执行计划。

4.3 Oracle SQL 优化

原始 SQL:

SELECT *
FROM orders
WHERE user_id = 10001
ORDER BY create_time DESC;

建立索引:

CREATE INDEX idx_orders_user_time
ON orders(user_id, create_time DESC);

优化 SQL:

SELECT
    id,
    order_no,
    amount,
    create_time
FROM orders
WHERE user_id = 10001
ORDER BY create_time DESC
FETCH FIRST 20 ROWS ONLY;

优化收益:

  • 减少扫描。
  • 降低排序成本。
  • 减少返回数据。

4.4 Oracle 索引优化

Oracle 常见索引:

索引类型 适用场景
B-Tree OLTP、高选择性查询
Bitmap 数据仓库、读多写少
Function-Based 函数表达式查询
Composite 多字段查询
Local Partitioned 分区表本地索引
Global Partitioned 跨分区查询及特定唯一性需求

B-Tree 索引

适合:

  • 用户 ID。
  • 订单 ID。
  • 角色 ID。
  • 交易流水 ID。

Bitmap 索引

适合:

  • 数据仓库。
  • 报表分析。
  • 低频更新数据。

不推荐在频繁更新的电商订单表或游戏交易表上随意使用 Bitmap 索引。

原因:

可能产生严重的并发更新争用。


4.5 Oracle 统计信息优化

Oracle 优化器依赖统计信息选择执行计划。

收集统计信息:

BEGIN
    DBMS_STATS.GATHER_TABLE_STATS(
        ownname => 'ECOMMERCE',
        tabname => 'ORDERS',
        cascade => TRUE
    );
END;
/

统计信息包括:

  • 表行数。
  • 数据块数量。
  • 列基数。
  • 数据分布。
  • 直方图。
  • 索引统计信息。

典型问题:

数据量从100万增长到1亿
          ↓
统计信息没有及时更新
          ↓
优化器错误估算数据量
          ↓
选择不合理的执行计划
          ↓
SQL执行速度下降

优化建议:

  1. 检查统计信息是否过期。
  2. 优先利用自动统计信息收集。
  3. 对分区表评估增量统计信息。
  4. 对数据倾斜字段评估直方图。
  5. 验证统计信息变化对执行计划的影响。

4.6 Oracle 分区表

示例:

CREATE TABLE orders (
    id NUMBER NOT NULL,
    user_id NUMBER NOT NULL,
    amount NUMBER(12,2),
    create_time DATE NOT NULL
)
PARTITION BY RANGE(create_time)
INTERVAL (NUMTOYMINTERVAL(1, 'MONTH'))
(
    PARTITION p_initial
    VALUES LESS THAN (DATE '2026-01-01')
);

特点:

  • 按月自动创建后续分区。
  • 支持分区裁剪。
  • 方便历史数据管理。
  • 可结合分区索引。

查询:

SELECT *
FROM orders
WHERE create_time >= DATE '2026-10-01'
  AND create_time < DATE '2026-11-01';

可以利用分区裁剪。


4.7 Oracle SGA 与 PGA 优化

Oracle 内存结构:

Oracle Instance
      │
      ├── SGA
      │    ├── Database Buffer Cache
      │    ├── Shared Pool
      │    ├── Redo Log Buffer
      │    └── 其他共享内存
      │
      └── PGA
           ├── 排序工作区
           ├── Hash Join工作区
           └── 会话私有内存

查看 SGA:

SHOW PARAMETER sga_target;

SHOW PARAMETER sga_max_size;

查看 PGA:

SHOW PARAMETER pga_aggregate_target;

SHOW PARAMETER pga_aggregate_limit;

优化重点:

  • Buffer Cache 是否存在明显压力。
  • Shared Pool 是否存在大量硬解析。
  • 排序是否频繁使用 TEMP。
  • Hash Join 是否大量落盘。
  • PGA 是否触及限制。

注意:

不能仅通过缓存命中率判断数据库性能。


4.8 Oracle Redo 与 Undo 优化

Redo

Redo 主要用于事务恢复。

高并发交易中:

玩家交易
   ↓
修改金币
   ↓
修改装备
   ↓
生成Redo
   ↓
提交事务

常见等待事件:

log file sync

排查方向:

  • Commit 频率。
  • Redo 写入延迟。
  • 存储性能。
  • 并发提交压力。

Undo

Undo 用于:

  • 事务回滚。
  • 一致性读取。
  • Flashback 等功能。

常见错误:

ORA-01555: snapshot too old

可能原因:

  • 长时间查询。
  • Undo 空间不足。
  • Undo 保留时间不匹配。
  • 高频更新导致旧版本被覆盖。

解决方向:

  • 优化长时间运行的 SQL。
  • 检查 Undo 空间。
  • 分析 Undo 使用情况。
  • 调整 Undo 保留策略。

五、电商业务数据库专项优化

5.1 秒杀库存优化

假设:

库存:100件

并发请求:100000

原始方案:

SELECT stock
FROM product_stock
WHERE product_id = 10001;

应用判断库存后:

UPDATE product_stock
SET stock = stock - 1
WHERE product_id = 10001;

问题:

多个请求可能同时读取相同库存值,产生并发逻辑错误。

优化:

UPDATE product_stock
SET stock = stock - 1
WHERE product_id = 10001
  AND stock > 0;

通过受影响行数判断扣减是否成功。

但大量请求仍然可能竞争同一库存行。

更高并发场景:

用户请求
    ↓
限流与防刷
    ↓
Redis库存预检查
    ↓
消息队列削峰
    ↓
订单消费者
    ↓
数据库条件扣减
    ↓
订单状态确认

需要注意:

  • Redis 预检查不等于最终扣减成功。
  • 必须保证幂等。
  • 需要库存预留和释放。
  • 需要处理消息重复消费。
  • 需要处理超时订单。
  • 需要处理支付与库存一致性。

5.2 电商订单冷热分离

假设:

订单总量:20亿

最近3个月:2亿

历史订单:18亿

可以设计:

订单查询入口
      │
      ├── 热数据订单库
      │      └── 最近订单
      │
      └── 历史订单库
             └── 历史订单

优点:

  1. 减少在线热数据规模。
  2. 降低历史数据对交易业务的影响。
  3. 降低在线数据库维护压力。
  4. 历史数据可以采用更低成本存储。

需要解决:

  • 数据迁移。
  • 查询路由。
  • 数据一致性。
  • 归档策略。
  • 历史订单查询。

5.3 电商读写分离

              应用服务
                 │
             数据访问层
                 │
        ┌────────┴────────┐
        │                 │
      主库               从库
      写入               查询
        │                 │
        └────数据复制─────┘

适合:

  • 商品详情。
  • 商品列表。
  • 历史订单。
  • 非强实时统计。

需要注意:

主从复制可能存在延迟。

因此:

  • 支付后立即读取订单。
  • 库存扣减后立即确认。
  • 订单状态变更后立即读取。

这些场景应考虑主库读取或其他一致性保障机制。


六、网络游戏数据库专项优化

6.1 游戏角色数据设计

常见数据表:

player
player_attribute
player_inventory
player_equipment
player_currency
player_quest
player_mail
player_transaction_log

金币表:

CREATE TABLE player_currency (
    player_id BIGINT PRIMARY KEY,
    gold BIGINT NOT NULL DEFAULT 0,
    diamond BIGINT NOT NULL DEFAULT 0,
    version BIGINT NOT NULL DEFAULT 0
);

扣除金币:

UPDATE player_currency
SET gold = gold - 100,
    version = version + 1
WHERE player_id = 10001
  AND gold >= 100;

通过受影响行数判断是否成功。

如果涉及多个角色、装备和金币,需要保证整个交易流程的数据一致性。


6.2 玩家数据缓存

大型 MMORPG 不适合把所有角色状态变化都立即写入数据库。

可以采用:

玩家登录
    ↓
加载角色数据
    ↓
游戏服务器内存维护状态
    ↓
战斗、升级、移动
    ↓
记录重要变更事件
    ↓
周期性保存检查点
    ↓
玩家下线持久化

但不能只依赖周期性保存。

否则服务器异常宕机可能造成数据丢失。

建议:

数据类型 持久化方式
角色坐标 周期性保存
临时战斗状态 内存维护
角色等级 关键事件持久化
金币、钻石 可靠事务或持久化事件
稀有装备 强一致持久化
玩家交易 事务、流水、幂等
战斗日志 异步写入
排行榜 Redis 或专用存储

6.3 游戏按区服分库

游戏网关
    │
    ├── 1区
    │    └── game_db_01
    │
    ├── 2区
    │    └── game_db_02
    │
    ├── 3区
    │    └── game_db_03
    │
    └── 跨服服务
         └── global_db

优点:

  • 区服之间隔离。
  • 降低单库压力。
  • 故障影响范围较小。
  • 方便扩容。

缺点:

  • 跨服交易复杂。
  • 合服需要数据迁移。
  • 全局排行榜需要汇总。
  • 角色 ID 需要全局唯一。
  • 热门区服可能负载过高。

6.4 游戏日志海量写入

假设:

在线玩家:50万人

每人每分钟产生10条日志

计算:

每分钟:500万条

每秒平均:约8.3万条

每天:72亿条

不建议把所有日志同步写入核心交易数据库。

推荐架构:

游戏服务器
     ↓
日志采集
     ↓
Kafka
     ↓
流式处理
     ↓
分析型数据库 / 对象存储
     ↓
运营分析、反作弊、报表

可评估:

  • ClickHouse。
  • Apache Doris。
  • Apache Iceberg。
  • 对象存储。

MySQL / Oracle 主要负责关键业务事务数据。


七、MySQL 与 Oracle 调优方案对比

调优维度 MySQL Oracle
SQL 分析 EXPLAIN ANALYZE DBMS_XPLAN
慢 SQL 定位 Slow Query Log V$SQL、ASH
SQL 统计 Performance Schema V$SQL、AWR
统计信息 ANALYZE TABLE、自动统计 DBMS_STATS
内存优化 Buffer Pool SGA、PGA
事务日志 Redo、Undo、Binlog Redo、Undo、Archive Log
索引 B-Tree 为主 B-Tree、Bitmap、函数索引
分区 RANGE、LIST、HASH RANGE、LIST、HASH、INTERVAL
读写扩展 主从复制、读写分离 Data Guard、Active Data Guard
高可用 InnoDB Cluster 等 RAC、Data Guard
水平扩展 分库分表、Vitess 等 Oracle Sharding 等
执行计划管理 优化器控制与版本相关能力 SQL Plan Management

注意:

Oracle RAC 不等于分库分表。

RAC 主要用于多实例共享数据库的高可用和部分负载扩展。


八、数据库调优常见问题

问题 原因 解决方案
SQL 突然变慢 执行计划变化 检查统计信息和执行计划
索引不生效 选择性低、条件不匹配 分析执行计划
CPU 100% 高频 SQL、复杂计算 SQL 优化、降低无效调用
I/O 很高 大量扫描、缓存不足 索引优化、检查存储
连接数耗尽 连接泄漏、连接池不合理 连接池治理
锁等待严重 长事务、热点行 缩短事务、降低竞争
死锁频繁 加锁顺序不一致 统一加锁顺序、幂等重试
INSERT 变慢 索引过多、存储压力 索引治理、批量写入
UPDATE 变慢 大范围更新、锁竞争 分批更新
DELETE 变慢 大事务 分批删除、分区归档
分页变慢 OFFSET 过大 游标分页
分区不提速 没有分区裁剪 优化分区条件
主从延迟 大事务、复制瓶颈 优化事务和复制
内存持续升高 连接内存、工作区问题 分析内存使用
ORA-01555 Undo 历史版本不足 检查长查询和 Undo
log file sync 高 Commit、Redo 写入延迟 检查提交频率和存储
MySQL Undo 堆积 长事务阻碍 Purge 排查长事务
扩容后仍然慢 SQL 或热点问题未解决 重新定位瓶颈
分库分表复杂 跨库查询和事务 优化数据边界
缓存与数据库不一致 更新顺序、复制延迟 一致性设计和补偿

九、生产环境调优常见风险

9.1 大表增加索引

ALTER TABLE orders
ADD INDEX idx_user_id(user_id);

风险:

  • 大量磁盘 I/O。
  • DDL 执行时间长。
  • 元数据锁等待。
  • 复制延迟。
  • 磁盘空间不足。

建议:

  • 在测试环境验证。
  • 检查在线 DDL 支持情况。
  • 选择业务低峰期。
  • 提前准备回滚方案。

9.2 大批量删除

不建议在业务高峰直接执行:

DELETE FROM game_log
WHERE create_time < '2025-01-01';

如果匹配几亿条数据,可能导致:

  • 大事务。
  • 大量 Undo / Redo。
  • 长时间锁等待。
  • 主从复制延迟。
  • 恢复成本增加。

优化方案:

  • 分批删除。
  • 按时间分区。
  • 历史数据归档。
  • 在低峰期执行。

9.3 盲目增加连接数

例如:

max_connections=10000

并不意味着数据库可以同时高效执行10000个复杂 SQL。

可能导致:

  • 内存消耗增加。
  • 线程调度成本增加。
  • 锁竞争加剧。
  • 数据库排队时间变长。

推荐:

  • 合理设置连接池。
  • 控制并发请求。
  • 配合限流和排队机制。
  • 根据实际负载测试调整。

9.4 Oracle 统计信息变化

统计信息更新后,执行计划可能变化。

风险:

原执行计划
    ↓
更新统计信息
    ↓
优化器重新选择计划
    ↓
关键SQL性能下降

建议:

  • 记录关键 SQL 执行计划。
  • 测试统计信息变化。
  • 必要时评估 SQL Plan Management。
  • 避免盲目使用 Hint。

十、数据库性能调优验证

优化不能只凭感觉。

必须对比优化前后的指标。

指标 优化前 优化后
SQL P95 800ms 80ms
SQL P99 3s 300ms
QPS 3000 6000
CPU 90% 55%
锁等待 频繁 明显减少
复制延迟 15s 1s

以上为示例数据,不代表保证收益。

验证流程:

记录性能基线
    ↓
准备测试数据
    ↓
复现业务负载
    ↓
实施单项优化
    ↓
执行压力测试
    ↓
对比性能指标
    ↓
验证数据一致性
    ↓
验证回滚方案
    ↓
灰度上线
    ↓
持续监控

重点关注:

  • P50 / P95 / P99 延迟。
  • QPS / TPS。
  • CPU。
  • 内存。
  • 磁盘 I/O。
  • 锁等待。
  • 复制延迟。
  • 数据一致性。
  • 故障恢复能力。

十一、不同数据规模的优化建议

以下数据规模仅用于规划参考,不是固定的架构切换阈值。

数据规模 MySQL Oracle
100万 SQL、索引 SQL、索引、统计信息
1000万 慢查询治理、缓存 执行计划、统计信息
1亿 归档、分区、读写分离评估 分区、SGA/PGA、索引策略
10亿 冷热分离、分片评估 分区、并行与存储优化
100亿 分布式架构、数据分层 分布式扩展、分析系统分离
更大规模 多层存储与服务化数据架构 按负载选择分布式方案

注意:

不要因为一张表达到1亿条数据就直接分库分表。

是否需要分库分表,取决于:

  • 单实例吞吐量是否达到瓶颈。
  • 数据访问模式。
  • 热点数据分布。
  • 数据增长速度。
  • 存储容量。
  • 运维复杂度。
  • 可接受的一致性成本。

十二、数据库调优排查流程图

数据库性能下降
       │
       ▼
采集性能指标
       │
       ▼
判断瓶颈类型
       │
       ├── CPU高
       │     ├── 高频SQL
       │     ├── 复杂计算
       │     └── 执行计划异常
       │
       ├── I/O高
       │     ├── 全表扫描
       │     ├── 缓存不足
       │     └── 大量写入
       │
       ├── 锁等待高
       │     ├── 长事务
       │     ├── 热点行
       │     └── 加锁顺序问题
       │
       ├── 内存压力
       │     ├── 缓存配置
       │     ├── 连接内存
       │     └── 排序工作区
       │
       └── 容量压力
             ├── 历史归档
             ├── 分区
             ├── 冷热分离
             └── 分库分表
       │
       ▼
制定优化方案
       │
       ▼
测试环境验证
       │
       ▼
灰度上线
       │
       ▼
持续监控

十三、MySQL 调优重点总结

需要重点掌握:

  1. 慢查询日志与 Performance Schema。
  2. EXPLAIN ANALYZE 执行计划分析。
  3. 联合索引与覆盖索引。
  4. InnoDB Buffer Pool。
  5. Redo Log 与 Undo。
  6. 事务与锁优化。
  7. 分区表。
  8. 分库分表。
  9. 主从复制与读写分离。
  10. Redis 缓存。
  11. 消息队列削峰。
  12. 数据库监控与容量规划。

十四、Oracle 调优重点总结

需要重点掌握:

  1. V$SQL、V$SESSION。
  2. DBMS_XPLAN。
  3. AWR、ASH、SQL Monitor。
  4. CBO 优化器。
  5. DBMS_STATS 统计信息。
  6. B-Tree、Bitmap、函数索引。
  7. 分区表与分区裁剪。
  8. SGA、PGA。
  9. Redo、Undo。
  10. RAC、Data Guard。
  11. SQL Plan Management。
  12. 等待事件分析。

十五、电商与网游数据库调优的核心区别

电商系统

重点解决:

  • 订单查询慢。
  • 库存热点竞争。
  • 秒杀高并发。
  • 支付一致性。
  • 订单历史数据增长。
  • 商品缓存。
  • 读写分离。
  • 分库分表。

核心目标:

提高订单处理能力,保证库存和支付正确性。

网络游戏系统

重点解决:

  • 玩家数据频繁更新。
  • 金币、装备交易一致性。
  • 角色状态缓存。
  • 热门区服负载。
  • 海量日志写入。
  • 游戏排行榜。
  • 跨服数据访问。
  • 合服数据迁移。

核心目标:

降低角色数据访问延迟,保证虚拟资产正确性,支撑大量玩家同时在线。


十六、最终总结

数据库性能调优可以概括为六个关键词:

SQL、索引、事务、内存、数据分层、架构。

MySQL

主要优化方向:

SQL优化
   ↓
索引优化
   ↓
InnoDB参数优化
   ↓
事务与锁优化
   ↓
分区与归档
   ↓
缓存与读写分离
   ↓
分库分表

Oracle

主要优化方向:

SQL优化
   ↓
执行计划分析
   ↓
统计信息优化
   ↓
索引与分区优化
   ↓
等待事件分析
   ↓
SGA/PGA优化
   ↓
Redo/Undo优化
   ↓
集群与架构优化

最重要的原则

数据库性能优化的本质,不是简单增加服务器资源,而是让高频业务以更低的资源成本访问必要的数据,同时让历史数据不干扰核心交易。

当数据规模达到数十亿甚至百亿级时,需要从单纯的数据库参数优化,逐步转向数据生命周期管理、缓存、分布式架构以及在线交易与分析型负载分离。

最终目标:高性能、高并发、高可用、数据一致性、可扩展性。


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言