Skip to content
第 234 / 250 章架构⏱ 12 分钟阅读

第 234 章:大数据量处理

学习目标

  • MySQL 亿级数据方案
  • 大表拆分策略
  • 分库分表实战
  • 离线 / 实时数仓

一、数据库容量

数据量现象优化手段
100 万流畅良好设计
1000 万部分场景慢索引优化
1 亿明显卡顿拆分 + 缓存
10 亿+危险分库分表 + 大数据

二、SQL 优化

2.1 索引失效场景

sql
-- 索引失效的常见写法
SELECT * FROM user WHERE SUBSTRING(name, 1, 2) = 'Tom';   -- 函数
SELECT * FROM user WHERE name + '1' = 'Tom1';              -- 表达式
SELECT * FROM user WHERE name LIKE '%Tom%';                 -- 前导 %
SELECT * FROM user WHERE id != 1;                           -- !=

2.2 索引设计原则

yaml
最左前缀:
  - 联合索引 (a, b, c) 可命中:
    ✅ WHERE a = 1
    ✅ WHERE a = 1 AND b = 2
    ✅ WHERE a = 1 AND b = 2 AND c = 3
    ❌ WHERE b = 2

覆盖索引: 索引包含全部查询列,不用回表
  - SELECT id FROM user WHERE age > 18;  -- id 是主键

下推: MySQL 5.6+ 的 ICP 优化自动
避免: SELECT *  ⇒ 指定列

2.3 深分页问题

sql
-- ❌ LIMIT 1000000, 10 慢(MySQL 跳过 100 万行)
SELECT * FROM orders LIMIT 1000000, 10;

-- ✅ 优化 1:子查询定位
SELECT * FROM orders
WHERE id > (SELECT id FROM orders ORDER BY id LIMIT 1000000, 1)
ORDER BY id LIMIT 10;

-- ✅ 优化 2:CURSOR 分页(上次位置)
SELECT * FROM orders WHERE id > 1000000 ORDER BY id LIMIT 10;

-- ✅ 优化 3: ES 全文搜索

三、垂直拆分

按业务拆分表,字段从一张 → 多张

适用:

  • 字段太多(> 50 列)
  • 大字段(TEXT, BLOB)
  • 不同字段访问频率差异大

四、水平拆分

按业务字段拆分,行从一张 → 多张

4.1 库内分表

sql
-- orders 表按月拆
orders_202601
orders_202602
orders_202603

4.2 分库分表

sql
-- 创建 4 个库,16 张表
ds0: orders_00 / orders_01 / orders_02 / orders_03
ds1: orders_04 / ...
ds2: ...
ds3: ...

4.3 拆分维度

维度适合例子
Hash(用户 ID)平衡但难迁移user_id % 4
Range(时间)简单,易归档2026_q1
地理多区域北京 / 上海
业务微服务订单 / 商品

4.4 ShardingSphere

引入

xml
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-jdbc-core</artifactId>
</dependency>

配置

yaml
spring:
  shardingsphere:
    datasource:
      names: ds0,ds1,ds2,ds3

    rules:
      sharding:
        tables:
          orders:
            actual-data-nodes: ds${0..3}.orders_${0..3}
            table-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: order_hash
            key-generator:
              column: order_id
              key-generator-name: snowflake
        sharding-algorithms:
          order_hash:
            type: inline
            props:
              algorithm-expression: orders_${order_id % 4}
        key-generators:
          snowflake:
            type: SNOWFLAKE

复杂查询

yaml
# 绑定表(关联查询在同库)
binding-tables:
  - orders, order_item

# 广播表(每个库都同步)
broadcast-tables:
  - product

读写分离

yaml
spring:
  shardingsphere:
    rules:
      readwrite-splitting:
        data-sources:
          ds0:
            write-data-source-name: ds0-master
            read-data-source-names:
              - ds0-slave-1
              - ds0-slave-2
            load-balancer-name: round-robin

五、分布式 ID

5.1 雪花算法(Snowflake)

0 | 41 bit 时间 | 10 bit 机器 | 12 bit 序列号 | 0
java
// Hutool / 美团 Leaf 都已实现
long id = snowflake.nextId();  // 657128827453235200

5.2 美团 Leaf

yaml
leaf.name=leaf
leaf.segment.enable=true

leaf.segment.url=jdbc:mysql://mysql:3306/leaf
leaf.segment.username=root
leaf.segment.password=root
java
@Autowired
private SegmentIDGenImpl segmentIDGen;

public long nextId() {
    Segment seg = segmentIDGen.get("order").get();
    return seg.nextId();
}

5.3 UUID

性能问题:占用大(128 bit)、无序(不能做聚集索引)

java
String id = UUID.randomUUID().toString().replace("-", "");   // 32 位

5.4 号段模式

sql
-- leaf_alloc 表
CREATE TABLE leaf_alloc (
    biz_tag VARCHAR(50),
    max_id BIGINT,
    step INT  -- 每次取一段
);

-- 一次发一段(如 1000-1999),用完再来
-- 性能极高,丢号就丢号

六、冷热数据分离

sql
-- 定时任务每月跑
INSERT INTO orders_archive
SELECT * FROM orders WHERE created_at < DATE_SUB(NOW(), INTERVAL 3 MONTH);

DELETE FROM orders WHERE created_at < DATE_SUB(NOW(), INTERVAL 3 MONTH);

七、大宽表 + 数据仓库

7.1 离线数仓

7.2 实时数仓

7.3 场景

场景工具
大宽表 SQL 分析ClickHouse / Doris / StarRocks
实时指标Flink + Druid
全文搜索Elasticsearch
图关系Neo4j
KV 查询HBase / Cassandra

八、Elasticsearch 大数据量

8.1 分片设计

json
POST /orders/_search
{
    "settings": {
        "number_of_shards": 6,
        "number_of_replicas": 1
    }
}

8.2 索引模板

json
PUT _index_template/orders_template
{
    "index_patterns": ["orders-*"],
    "template": {
        "settings": {
            "number_of_shards": 6,
            "number_of_replicas": 1,
            "analysis": {
                "analyzer": {
                    "ik_max_word": {
                        "type": "ik_max_word"
                    }
                }
            }
        }
    }
}

8.3 滚动索引

bash
POST /orders-2026.01/_rollover
{
    "conditions": {
        "max_age": "30d",
        "max_docs": 100000000
    }
}

九、ClickHouse

适合海量数据 OLAP 分析场景,性能超 MySQL 100x。

sql
-- 创建表
CREATE TABLE events (
    event_date Date,
    user_id UInt64,
    event_type String,
    amount Decimal(10, 2)
) ENGINE = MergeTree()
PARTITION BY event_date
ORDER BY (user_id, event_date);

-- 高性能查询
SELECT
    toStartOfHour(event_date) AS hour,
    count() AS events,
    uniqExact(user_id) AS unique_users
FROM events
WHERE event_date >= '2026-01-01'
GROUP BY hour
ORDER BY hour;

十、归档与日志

十一、本章小结

数据量级方案
< 千万索引 + SQL 优化
千万级缓存 + 读写分离
亿级分库分表
十亿+大数据平台

动手练习

  1. 给"订单表"做水平拆分,设计 ShardingSphere 配置
  2. 用 Leaf 生成分布式 ID
  3. 把订单归档到冷库,只保留最近 3 个月
  4. 用 ClickHouse 统计某日订单汇总

下一章:第 235 章:系统监控与故障应急

本站基于 VitePress 构建 · 由 Codebook 团队维护