第 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_2026034.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 序列号 | 0java
// Hutool / 美团 Leaf 都已实现
long id = snowflake.nextId(); // 6571288274532352005.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=rootjava
@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 优化 |
| 千万级 | 缓存 + 读写分离 |
| 亿级 | 分库分表 |
| 十亿+ | 大数据平台 |
动手练习
- 给"订单表"做水平拆分,设计 ShardingSphere 配置
- 用 Leaf 生成分布式 ID
- 把订单归档到冷库,只保留最近 3 个月
- 用 ClickHouse 统计某日订单汇总