向量数据库选型与对比完全教程
适用读者:AI 工程师、后端架构师、技术决策者
最后更新:2025 年 5 月
阅读时长:约 25 分钟
目录
- 为什么需要向量数据库
- 核心概念与关键指标
- 六大主流向量数据库深度对比
- 性能基准测试
- 部署方案对比:本地 vs 云端 vs 混合
- 混合检索支持
- 可扩展性评估
- 成本分析
- 选型决策框架
- 与 RAG 系统集成实战
- 未来发展趋势
- 总结
1. 为什么需要向量数据库
传统关系型数据库擅长精确匹配和结构化查询,但在处理语义相似性搜索时力不从心。当用户搜索"如何让代码运行更快"时,我们希望匹配到"性能优化技巧"、"程序加速方法"等语义相近的内容——这正是向量数据库的用武之地。
向量数据库的核心价值:
- 语义搜索:基于含义而非关键词匹配
- 多模态检索:文本、图片、音频统一向量化后可跨模态搜索
- AI 应用基石:RAG(检索增强生成)、推荐系统、异常检测的底层支撑
- 高维数据管理:高效存储和检索 Embedding 向量(768~4096 维)
# 传统搜索 vs 向量搜索的核心区别
# 传统搜索:关键词匹配
results = db.query("SELECT * FROM docs WHERE title LIKE '%性能优化%'")
# 向量搜索:语义匹配
query_embedding = model.encode("如何让代码运行更快")
results = vector_db.search(query_embedding, top_k=10)
# 返回结果包含"性能优化技巧"、"程序加速方法"、"缓存策略"等语义相关内容
2. 核心概念与关键指标
2.1 向量索引类型
| 索引类型 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| HNSW | 分层可导航小世界图 | 查询快、精度高 | 内存占用大、构建慢 |
| IVF | 倒排文件索引 | 内存效率好 | 精度依赖 nprobe 参数 |
| Flat | 暴力搜索 | 100% 精确 | 数据量大时极慢 |
| PQ | 乘积量化 | 压缩率高 | 精度有损 |
| ScaNN | Google 的可扩展近似最近邻 | 速度/精度平衡好 | 生态较封闭 |
2.2 关键性能指标
- QPS(Queries Per Second):每秒查询数,衡量吞吐量
- 延迟(Latency):单次查询耗时,通常看 P50/P95/P99
- 召回率(Recall):返回结果中正确结果的占比,衡量精度
- 内存占用:索引和数据在内存中的大小
- 构建时间:索引从零构建所需时间
# 性能基准测试示例代码
import time
import numpy as np
def benchmark(db, queries, ground_truth, top_k=10):
"""通用向量数据库基准测试"""
latencies = []
recalls = []
for query, gt in zip(queries, ground_truth):
start = time.perf_counter()
results = db.search(query, top_k=top_k)
elapsed = time.perf_counter() - start
latencies.append(elapsed)
# 计算召回率
retrieved_ids = set(r.id for r in results)
gt_ids = set(gt[:top_k])
recall = len(retrieved_ids & gt_ids) / len(gt_ids)
recalls.append(recall)
return {
"qps": len(queries) / sum(latencies),
"p50_latency_ms": np.percentile(latencies, 50) * 1000,
"p99_latency_ms": np.percentile(latencies, 99) * 1000,
"avg_recall": np.mean(recalls)
}
3. 六大主流向量数据库深度对比
3.1 Chroma
定位:轻量级、开发者友好的嵌入式向量数据库
import chromadb
# Chroma 基本使用
client = chromadb.Client() # 内存模式
# client = chromadb.PersistentClient(path="./chroma_db") # 持久化
collection = client.create_collection(
name="documents",
metadata={"hnsw:space": "cosine"}
)
# 批量插入
collection.add(
documents=["机器学习入门", "深度学习实战", "自然语言处理基础"],
metadatas=[{"source": "book"}, {"source": "course"}, {"source": "blog"}],
ids=["doc1", "doc2", "doc3"]
)
# 查询
results = collection.query(
query_texts=["AI 教程"],
n_results=2,
where={"source": "book"} # 支持元数据过滤
)
优势:上手极快、内置 Embedding 函数、与 LangChain 深度集成
劣势:不适合大规模生产环境、单机架构、缺乏分布式支持
适用场景:原型开发、小型项目、本地实验
3.2 Milvus
定位:面向大规模生产环境的分布式向量数据库
from pymilvus import (
connections, Collection, FieldSchema,
CollectionSchema, DataType, utility
)
# 连接 Milvus
connections.connect("default", host="localhost", port="19530")
# 定义 Schema
fields = [
FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True),
FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=768),
FieldSchema(name="text", dtype=DataType.VARCHAR, max_length=2000),
FieldSchema(name="category", dtype=DataType.VARCHAR, max_length=100),
]
schema = CollectionSchema(fields, description="文档向量集合")
collection = Collection("documents", schema)
# 创建索引
index_params = {
"metric_type": "COSINE",
"index_type": "HNSW",
"params": {"M": 16, "efConstruction": 200}
}
collection.create_index("embedding", index_params)
# 插入数据
import random
data = [
["这是一段测试文本"] * 1000, # text
[random.choice(["tech", "science"])] * 1000, # category
[[random.random() for _ in range(768)] for _ in range(1000)] # embedding
]
collection.insert(data)
# 搜索(带标量过滤)
collection.load()
results = collection.search(
data=[query_vector],
anns_field="embedding",
param={"metric_type": "COSINE", "params": {"ef": 128}},
limit=10,
expr='category == "tech"', # 混合检索
output_fields=["text", "category"]
)
优势:真正的分布式架构、支持万亿级向量、GPU 加速索引、丰富的 SDK
劣势:部署复杂(依赖 etcd/MinIO/Pulsar)、运维成本高
适用场景:大规模企业级应用、十亿级以上数据量
3.3 Qdrant
定位:高性能、易用的向量搜索引擎
from qdrant_client import QdrantClient
from qdrant_client.models import (
Distance, VectorParams, PointStruct,
Filter, FieldCondition, MatchValue
)
client = QdrantClient(host="localhost", port=6333)
# 创建集合
client.create_collection(
collection_name="documents",
vectors_config=VectorParams(size=768, distance=Distance.COSINE),
)
# 插入数据
client.upsert(
collection_name="documents",
points=[
PointStruct(
id=1,
vector=[0.1] * 768,
payload={"text": "向量数据库教程", "category": "tech", "year": 2025}
),
PointStruct(
id=2,
vector=[0.2] * 768,
payload={"text": "机器学习指南", "category": "science", "year": 2024}
),
]
)
# 搜索(带过滤)
results = client.search(
collection_name="documents",
query_vector=[0.15] * 768,
query_filter=Filter(
must=[
FieldCondition(key="category", match=MatchValue(value="tech")),
FieldCondition(key="year", range={"gte": 2024}),
]
),
limit=5,
with_payload=True,
)
优势:Rust 编写性能优异、过滤查询强大、API 设计优雅、支持多向量
劣势:集群能力不如 Milvus 成熟、生态相对较小
适用场景:中等规模生产环境、需要复杂过滤的场景
3.4 Weaviate
定位:AI 原生的向量数据库,内置向量化能力
import weaviate
client = weaviate.Client("http://localhost:8080")
# 创建类(Schema)
client.schema.create_class({
"class": "Document",
"vectorizer": "text2vec-openai", # 内置向量化
"properties": [
{"name": "content", "dataType": ["text"]},
{"name": "category", "dataType": ["text"]},
]
})
# 插入数据(自动向量化)
client.data_object.create(
{"content": "向量数据库选型指南", "category": "tech"},
"Document"
)
# 混合搜索:向量 + BM25
result = (
client.query
.get("Document", ["content", "category"])
.with_hybrid(
query="数据库教程",
alpha=0.75 # 0=纯BM25, 1=纯向量
)
.with_limit(10)
.do()
)
# 生成式搜索(内置 RAG)
result = (
client.query
.get("Document", ["content"])
.with_ask({"question": "什么是向量数据库?"})
.with_limit(5)
.do()
)
优势:内置向量化模块、原生混合搜索、GraphQL API、Generative Search
劣势:性能不如 Qdrant/Milvus、学习曲线较陡、社区相对小
适用场景:需要内置 AI 能力的全栈应用、RAG 原型
3.5 FAISS
定位:Facebook 开源的向量检索库(非数据库)
import faiss
import numpy as np
# 构建索引
dimension = 768
num_vectors = 100000
# 生成测试数据
vectors = np.random.random((num_vectors, dimension)).astype('float32')
# HNSW 索引
index = faiss.IndexHNSWFlat(dimension, 32)
index.hnsw.efConstruction = 200
index.add(vectors)
# 或 IVF + PQ 索引(适合大规模数据)
nlist = 100 # 聚类中心数
m = 32 # PQ 子空间数
quantizer = faiss.IndexFlatL2(dimension)
index_ivf = faiss.IndexIVFPQ(quantizer, dimension, nlist, m, 8)
index_ivf.train(vectors)
index_ivf.add(vectors)
index_ivf.nprobe = 10 # 搜索时检查的聚类数
# 搜索
query = np.random.random((1, dimension)).astype('float32')
distances, indices = index.search(query, k=10)
# GPU 加速
gpu_index = faiss.index_cpu_to_all_gpus(index)
distances, indices = gpu_index.search(query, k=10)
优势:极致性能(C++ 编写)、GPU 加速成熟、丰富的索引算法、学术界标准
劣势:纯库非数据库(无持久化/分布式/过滤)、需要自行封装服务层
适用场景:对性能要求极高的场景、研究项目、已有数据管道的补充
3.6 Pinecone
定位:全托管云向量数据库
import pinecone
# 初始化(全托管服务)
pinecone.init(api_key="YOUR_API_KEY", environment="us-east1-gcp")
# 创建索引
pinecone.create_index(
name="documents",
dimension=768,
metric="cosine",
pod_type="p1.x1" # 性能规格
)
index = pinecone.Index("documents")
# 插入数据
index.upsert([
("doc1", [0.1] * 768, {"text": "教程一", "category": "tech"}),
("doc2", [0.2] * 768, {"text": "教程二", "category": "science"}),
])
# 搜索(带元数据过滤)
results = index.query(
vector=[0.15] * 768,
top_k=10,
include_metadata=True,
filter={"category": {"$eq": "tech"}}
)
优势:零运维、自动扩缩容、毫秒级延迟、与主流 AI 框架集成好
劣势:成本较高、供应商锁定、数据主权受限
适用场景:不想运维的团队、快速上线的 SaaS 产品
3.7 综合对比表
| 维度 | Chroma | Milvus | Qdrant | Weaviate | FAISS | Pinecone |
|---|---|---|---|---|---|---|
| 架构 | 嵌入式 | 分布式 | 单机/集群 | 单机/集群 | 库 | 全托管云 |
| 语言 | Python | Go/C++ | Rust | Go | C++ | - |
| 最大数据量 | 百万级 | 万亿级 | 十亿级 | 十亿级 | 取决于内存 | 无上限 |
| 延迟(P99) | ~50ms | ~10ms | ~5ms | ~20ms | ~1ms | ~10ms |
| 混合检索 | 有限 | ✅ | ✅ | ✅ 原生 | ❌ | ✅ |
| 多向量 | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
| 开源 | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| 学习曲线 | 低 | 高 | 中 | 中 | 中 | 低 |
| 生产就绪 | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
4. 性能基准测试
4.1 ANN-Benchmarks 参考数据
基于标准 ANN-Benchmarks 测试(100 万条 128 维向量,Recall@10 ≥ 0.95):
| 数据库 | QPS | P99 延迟 | 内存占用 | 召回率 |
|---|---|---|---|---|
| FAISS (HNSW) | 15,000 | 2ms | 2.1 GB | 98.5% |
| Qdrant | 12,000 | 3ms | 2.3 GB | 98.2% |
| Milvus (HNSW) | 10,000 | 4ms | 2.5 GB | 98.0% |
| Weaviate | 6,000 | 8ms | 3.0 GB | 97.5% |
| Chroma | 3,000 | 15ms | 2.8 GB | 97.0% |
| Pinecone | 8,000 | 5ms | - (托管) | 98.0% |
注意:以上数据为近似参考值,实际性能受硬件、数据分布、索引参数等因素影响。
4.2 大规模测试场景
# 使用 ann-benchmarks 进行标准化测试
# 安装:pip install ann-benchmarks
import h5py
import numpy as np
def load_dataset(name):
"""加载标准测试数据集"""
f = h5py.File(f"{name}.hdf5", "r")
return {
"train": np.array(f["train"]),
"test": np.array(f["test"]),
"neighbors": np.array(f["neighbors"]),
"distances": np.array(f["distances"]),
}
# 常用测试数据集
# - sift-128-euclidean: 100万条128维向量
# - glove-100-angular: 118万条100维词向量
# - nytimes-256-angular: 29万条256维新闻向量
dataset = load_dataset("sift-128-euclidean")
5. 部署方案对比:本地 vs 云端 vs 混合
5.1 本地部署
# docker-compose.yml - Milvus 本地部署
version: '3.5'
services:
etcd:
image: quay.io/coreos/etcd:v3.5.5
environment:
- ETCD_AUTO_COMPACTION_MODE=revision
- ETCD_AUTO_COMPACTION_RETENTION=1000
minio:
image: minio/minio:RELEASE.2023-03-20T20-16-18Z
environment:
MINIO_ACCESS_KEY: minioadmin
MINIO_SECRET_KEY: minioadmin
command: minio server /minio_data
milvus-standalone:
image: milvusdb/milvus:v2.3.0
command: ["milvus", "run", "standalone"]
environment:
ETCD_ENDPOINTS: etcd:2379
MINIO_ADDRESS: minio:9000
ports:
- "19530:19530"
- "9091:9091"
depends_on:
- etcd
- minio
5.2 云端部署
| 服务商 | 向量数据库方案 | 特点 |
|---|---|---|
| AWS | OpenSearch + k-NN 插件 | 与 AWS 生态深度集成 |
| GCP | Vertex AI Vector Search | Google 全托管 |
| Azure | Azure AI Search | 企业级 SLA |
| 阿里云 | AnalyticDB PostgreSQL 向量版 | 国内合规 |
| 腾讯云 | Tencent Cloud VectorDB | 与微信生态集成 |
5.3 混合部署策略
# 混合部署:热数据本地 + 冷数据云端
class HybridVectorStore:
def __init__(self):
self.hot_store = QdrantClient(host="localhost") # 热数据
self.cold_store = Pinecone(api_key="...") # 冷数据
self.ttl_days = 30 # 热数据 TTL
def search(self, query_vector, top_k=10):
# 先搜索热数据
hot_results = self.hot_store.search(
collection_name="hot",
query_vector=query_vector,
limit=top_k
)
# 热数据不足时搜索冷数据
if len(hot_results) < top_k:
cold_results = self.cold_store.query(
vector=query_vector,
top_k=top_k - len(hot_results)
)
hot_results.extend(cold_results)
return hot_results[:top_k]
def archive_cold_data(self):
"""定期将冷数据归档到云端"""
cutoff = datetime.now() - timedelta(days=self.ttl_days)
# 迁移逻辑...
6. 混合检索支持
混合检索(Hybrid Search)结合向量搜索和传统关键词搜索,是当前 RAG 系统的最佳实践。
6.1 各数据库混合检索能力
| 数据库 | 向量搜索 | 全文搜索 | 混合策略 | 融合方法 |
|---|---|---|---|---|
| Milvus | ✅ | ✅ (2.4+) | RRF | 内置 |
| Qdrant | ✅ | ❌ (需外部) | 自定义 | 手动融合 |
| Weaviate | ✅ | ✅ (BM25) | 原生混合 | 内置 alpha 参数 |
| Chroma | ✅ | ❌ | 自定义 | 手动融合 |
| Pinecone | ✅ | ❌ | 稀疏-密集 | 内置 |
6.2 RRF 融合算法实现
def reciprocal_rank_fusion(results_list, k=60):
"""
Reciprocal Rank Fusion (RRF) 融合多路检索结果
k: 平滑参数,通常设为 60
"""
scores = {}
for results in results_list:
for rank, item in enumerate(results, 1):
doc_id = item["id"]
scores[doc_id] = scores.get(doc_id, 0) + 1 / (k + rank)
# 按融合分数排序
sorted_items = sorted(scores.items(), key=lambda x: x[1], reverse=True)
return sorted_items
# 使用示例
vector_results = vector_db.search(query_embedding, top_k=20)
bm25_results = bm25_index.search(query_text, top_k=20)
fused = reciprocal_rank_fusion([vector_results, bm25_results])
7. 可扩展性评估
7.1 水平扩展能力
Chroma Milvus Qdrant Weaviate FAISS Pinecone
单机上限 1M 10M 5M 5M 取决于RAM 无限
集群支持 ❌ ✅ ✅ ✅ ❌ ✅(托管)
自动分片 ❌ ✅ ✅ ❌ ❌ ✅
读写分离 ❌ ✅ ✅ ❌ ❌ ✅
在线扩缩容 ❌ ✅ ✅ ❌ ❌ ✅
7.2 数据增长规划
def estimate_resources(num_vectors, dimension, index_type="HNSW"):
"""估算向量数据库所需资源"""
# 内存估算
vector_memory = num_vectors * dimension * 4 # float32
index_overhead = {
"HNSW": 1.5, # HNSW 索引额外约 50% 开销
"IVF": 1.1, # IVF 索引额外约 10% 开销
"Flat": 1.0, # 暴力搜索无额外开销
}
total_memory = vector_memory * index_overhead.get(index_type, 1.0)
return {
"raw_vectors_gb": vector_memory / (1024**3),
"total_memory_gb": total_memory / (1024**3),
"recommended_ram_gb": total_memory * 1.2 / (1024**3), # 20% 余量
}
# 估算示例
resources = estimate_resources(
num_vectors=10_000_000,
dimension=768,
index_type="HNSW"
)
# 输出:{'raw_vectors_gb': 28.6, 'total_memory_gb': 42.9, 'recommended_ram_gb': 51.5}
8. 成本分析
8.1 自建 vs 托管成本对比(10 亿向量规模)
| 成本项 | 自建 Milvus | Pinecone | Qdrant Cloud |
|---|---|---|---|
| 计算 | $2,000/月 (3节点) | 按量计费 | $1,500/月 |
| 存储 | $500/月 (SSD) | 包含在内 | $400/月 |
| 运维人力 | $3,000/月 (0.5 FTE) | $0 | $500/月 (轻运维) |
| 总计 | $5,500/月 | $4,000~8,000/月 | $2,400/月 |
| 优势 | 数据可控 | 零运维 | 性价比高 |
8.2 成本优化策略
# 策略1:分层存储
class TieredStorage:
def __init__(self):
self.tiers = {
"hot": {"store": "qdrant", "max_age_days": 7},
"warm": {"store": "milvus_ssd", "max_age_days": 30},
"cold": {"store": "milvus_hdd", "max_age_days": 365},
}
def route_query(self, query_vector, filters=None):
"""根据数据温度路由查询"""
for tier_name, tier in self.tiers.items():
results = tier["store"].search(query_vector, filters)
if results:
return results
return []
# 策略2:量化压缩(减少内存占用)
# 使用 PQ 或标量量化,内存可减少 4~8 倍,精度损失 2~5%
9. 选型决策框架
9.1 决策树
开始选型
│
├── 数据量 < 100万?
│ ├── 是 → 需要快速原型?
│ │ ├── 是 → Chroma
│ │ └── 否 → Qdrant (单机)
│ └── 否 → 数据量 < 10亿?
│ ├── 是 → 需要混合搜索?
│ │ ├── 是 → Weaviate 或 Milvus
│ │ └── 否 → Qdrant
│ └── 否 → Milvus 集群 或 Pinecone
│
├── 不想运维?
│ └── Pinecone / 云托管方案
│
├── 极致性能要求?
│ └── FAISS + 自建服务层
│
└── 需要内置 AI 能力?
└── Weaviate
9.2 场景推荐矩阵
| 应用场景 | 首选 | 备选 | 理由 |
|---|---|---|---|
| RAG 原型 | Chroma | Qdrant | 上手快、集成好 |
| 企业 RAG | Milvus | Qdrant | 可扩展、稳定 |
| 语义搜索 SaaS | Qdrant | Pinecone | 性能好、易用 |
| 推荐系统 | Milvus | Pinecone | 大数据量、实时更新 |
| 图像检索 | FAISS | Milvus | 性能极致 |
| 全栈 AI 应用 | Weaviate | Chroma | 内置向量化 |
10. 与 RAG 系统集成实战
10.1 LangChain + Qdrant RAG 实现
from langchain.vectorstores import Qdrant
from langchain.embeddings import OpenAIEmbeddings
from langchain.chat_models import ChatOpenAI
from langchain.chains import RetrievalQA
from langchain.document_loaders import TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 1. 文档加载与分块
loader = TextLoader("knowledge_base.txt")
documents = loader.load()
splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50,
separators=["\n\n", "\n", "。", "!", "?"]
)
chunks = splitter.split_documents(documents)
# 2. 向量化并存入 Qdrant
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Qdrant.from_documents(
chunks,
embeddings,
location="localhost:6333",
collection_name="rag_docs",
)
# 3. 构建 RAG 链
llm = ChatOpenAI(model="gpt-4o", temperature=0)
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=vectorstore.as_retriever(
search_type="mmr", # 最大边际相关性
search_kwargs={"k": 5}
),
return_source_documents=True,
)
# 4. 查询
result = qa_chain.invoke({"query": "向量数据库如何选择?"})
print(result["result"])
for doc in result["source_documents"]:
print(f"来源: {doc.metadata['source']}, 内容: {doc.page_content[:100]}")
10.2 混合检索 RAG 优化
from langchain.retrievers import EnsembleRetriever
from langchain.retrievers import BM25Retriever
# 构建 BM25 检索器
bm25_retriever = BM25Retriever.from_documents(chunks)
bm25_retriever.k = 5
# 构建向量检索器
vector_retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
# 集成检索(RRF 融合)
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, vector_retriever],
weights=[0.4, 0.6] # BM25 权重 40%,向量权重 60%
)
# 用于 RAG
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
retriever=ensemble_retriever,
return_source_documents=True,
)
11. 未来发展趋势
11.1 技术趋势
- 多模态原生:向量数据库将原生支持文本、图像、音频、视频的统一存储和检索
- GPU 加速普及:从 NVIDIA RAPIDS 到专用硬件,GPU 向量搜索将成为标配
- Serverless 化:按查询计费、自动休眠、零运维成为主流
- SQL + 向量融合:PostgreSQL (pgvector)、ClickHouse 等传统数据库加入向量能力
- 边缘部署:轻量级向量搜索引擎适配边缘设备和移动端
11.2 生态趋势
- 标准化 API:行业趋向统一的查询接口
- 与 LLM 深度集成:向量数据库成为 LLM 应用的标准组件
- 安全与合规:数据加密、访问控制、审计日志成为必备功能
- 成本持续下降:量化技术和硬件进步推动成本降低
12. 总结
选择向量数据库没有"银弹",关键在于匹配你的具体需求:
| 如果你是... | 推荐 |
|---|---|
| 快速验证想法的开发者 | Chroma — 5 分钟上手 |
| 构建生产级 RAG 的团队 | Qdrant — 性能与易用平衡 |
| 处理十亿级数据的企业 | Milvus — 分布式能力最强 |
| 需要全栈 AI 能力 | Weaviate — 内置向量化和混合搜索 |
| 追求极致性能 | FAISS — 无出其右 |
| 不想运维 | Pinecone — 全托管零负担 |
最终建议:从 Qdrant 或 Chroma 开始原型开发,随着数据量和需求增长,再评估迁移到 Milvus 或云托管方案。向量数据库是 AI 应用的基础设施,选型时不仅要考虑当前需求,还要为未来 6~12 个月的增长预留空间。
参考资源