MongoDB vs Redis vs Elasticsearch:2026 年 NoSQL 数据库选型指南

6 阅读7分钟

90% 的 NoSQL 选型纠结,本质上是没搞清楚「你要解决什么问题」。这篇文章用 5 个真实场景 + 对比表格 + 完整代码,帮你一次性搞懂 MongoDB、Redis、Elasticsearch 到底该选谁。

一张图搞懂三者的定位

对比维度MongoDBRedisElasticsearch
数据模型文档(BSON/JSON)键值对 + 数据结构文档(JSON)
核心能力灵活存储、事务支持极速读写、数据结构丰富全文检索、聚合分析
持久化磁盘优先,WiredTiger内存优先,RDB/AOF 可选磁盘(Lucene 倒排索引)
查询语言MQL(类 SQL)命令式 APIDSL(JSON 格式)
事务支持4.0+ 支持多文档事务Lua 脚本保证原子性不支持跨文档事务
典型 QPS万级十万级千级(复杂查询)
适用场景通用数据存储缓存/实时排行榜/会话搜索/日志/数据分析

一句话总结

  • MongoDB — 啥都能存的万能瑞士军刀
  • Redis — 快到飞起的内存缓存之王
  • Elasticsearch — 搜索和分析的终极武器

场景 1:用户画像存储 → 选 MongoDB

需求:存储用户资料,字段经常变(今天加个「兴趣爱好」,明天加个「社交账号」),还要按条件查询。

# pip install pymongo
from pymongo import MongoClient, ASCENDING, DESCENDING

client = MongoClient("mongodb://localhost:27017")
db = client["user_profile"]
users = db["users"]

# 插入 — 字段完全自由,不需要提前建表
users.insert_many([
    {
        "name": "张三",
        "age": 28,
        "tags": ["Python", "云原生"],
        "address": {"city": "郑州", "district": "金水区"},
    },
    {
        "name": "李四",
        "age": 35,
        "tags": ["Go", "K8s"],
        "company": "某大厂",       # 李四多了个字段,完全没问题
        "address": {"city": "北京", "district": "海淀区"},
    },
])

# 灵活查询 — 按城市 + 年龄范围
results = users.find({
    "address.city": "郑州",
    "age": {"$gte": 25, "$lte": 30},
}).sort("age", ASCENDING)

for r in results:
    print(r)

# 建索引加速
users.create_index([("address.city", ASCENDING), ("age", ASCENDING)])

# 更新 — 给所有郑州用户加个标签
users.update_many(
    {"address.city": "郑州"},
    {"$addToSet": {"tags": "河南老乡"}},
)

为什么不用 Redis? Redis 存复杂嵌套结构要手动序列化,查询能力弱。 为什么不用 ES? ES 更适合搜索,不是通用存储引擎,写放大问题明显。

场景 2:实时排行榜 + 限流 → 选 Redis

需求:游戏排行榜 Top 100,API 限流每用户 100 次/分钟。

# pip install redis
import redis
import time
import json

r = redis.Redis(host="localhost", port=6379, db=0, decode_responses=True)

# ===== 排行榜:用 Sorted Set =====
leaderboard_key = "game:ranking:season1"

# 批量添加分数
r.zadd(leaderboard_key, {
    "player_001": 9800,
    "player_002": 12500,
    "player_003": 11000,
    "player_004": 8900,
    "player_005": 15000,
})

# 增加某玩家分数
r.zincrby(leaderboard_key, 300, "player_001")

# 获取 Top 3(分数从高到低)
top3 = r.zrevrange(leaderboard_key, 0, 2, withscores=True)
print("🏆 Top 3:")
for name, score in top3:
    print(f"  {name}: {int(score)} 分")

# 查某玩家排名
rank = r.zrevrank(leaderboard_key, "player_001")
print(f"player_001 排名: 第 {rank + 1} 名")


# ===== API 限流:用 String + TTL =====
def check_rate_limit(user_id: str, max_requests: int = 100, window: int = 60) -> bool:
    """滑动窗口限流:每用户每分钟最多 max_requests 次请求"""
    key = f"rate_limit:{user_id}"
    current = r.get(key)
    if current is None:
        r.setex(key, window, 1)
        return True
    if int(current) >= max_requests:
        return False
    r.incr(key)
    return True

# 测试限流
for i in range(105):
    allowed = check_rate_limit("user_123", max_requests=100)
    if not allowed:
        print(f"🚫 第 {i+1} 次请求被限流")
        break

为什么不用 MongoDB? 排行榜需要实时排序,MongoDB 排序要走磁盘,性能差几个数量级。 为什么不用 ES? 限流需要毫秒级读写,ES 的写入延迟不适合。

场景 3:商品搜索 + 聚合分析 → 选 Elasticsearch

需求:电商商品搜索,支持中文分词、多条件筛选、价格聚合。

# pip install elasticsearch
from elasticsearch import Elasticsearch
from elasticsearch.helpers import bulk

es = Elasticsearch("http://localhost:9200")

# 创建索引,配置中文分词器
index_name = "products"
if es.indices.exists(index=index_name):
    es.indices.delete(index=index_name)

es.indices.create(index=index_name, body={
    "settings": {
        "analysis": {
            "analyzer": {
                "ik_smart_analyzer": {
                    "type": "custom",
                    "tokenizer": "ik_max_word"    # 需要安装 ik 分词插件
                }
            }
        }
    },
    "mappings": {
        "properties": {
            "name": {"type": "text", "analyzer": "ik_smart_analyzer"},
            "category": {"type": "keyword"},
            "price": {"type": "float"},
            "brand": {"type": "keyword"},
            "tags": {"type": "keyword"},
        }
    }
})

# 批量写入商品
products = [
    {"name": "腾讯云轻量应用服务器 2核4G", "category": "云服务器", "price": 68.0, "brand": "腾讯云", "tags": ["入门", "高性价比"]},
    {"name": "阿里云 ECS 通用型 4核8G", "category": "云服务器", "price": 156.0, "brand": "阿里云", "tags": ["企业级", "稳定"]},
    {"name": "华为云耀云服务器 2核2G", "category": "云服务器", "price": 49.0, "brand": "华为云", "tags": ["入门", "低价"]},
    {"name": "大模型 API 调用包 100万 Token", "category": "AI 服务", "price": 29.9, "brand": "混元", "tags": ["AI", "大模型"]},
]

actions = [
    {"_index": index_name, "_source": p}
    for p in products
]
bulk(es, actions)

# 搜索:云服务器 + 价格 < 100
result = es.search(index=index_name, body={
    "query": {
        "bool": {
            "must": [
                {"match": {"name": "云服务器"}},
            ],
            "filter": [
                {"range": {"price": {"lte": 100}}}
            ]
        }
    },
    "aggs": {
        "brand_stats": {
            "terms": {"field": "brand", "size": 10}
        },
        "price_ranges": {
            "range": {
                "field": "price",
                "ranges": [
                    {"key": "0-50", "to": 50},
                    {"key": "50-100", "from": 50, "to": 100},
                    {"key": "100+", "from": 100},
                ]
            }
        }
    }
})

print("搜索结果:")
for hit in result["hits"]["hits"]:
    src = hit["_source"]
    print(f"  {src['name']} - ¥{src['price']} ({src['brand']})")

print("\n品牌分布:")
for bucket in result["aggregations"]["brand_stats"]["buckets"]:
    print(f"  {bucket['key']}: {bucket['doc_count']} 个商品")

为什么不用 MongoDB? MongoDB 的文本搜索能力有限,中文分词支持差,聚合分析不如 ES 灵活。 为什么不用 Redis? Redis 的搜索模块(RediSearch)功能远不如 ES,生态差距大。

场景 4:混合架构 — 三者搭配才是王道

真实项目往往是三者搭配使用:

层次技术职责
缓存层Redis热点数据缓存、会话管理、限流
存储层MongoDB核心业务数据持久化
搜索层Elasticsearch全文检索、日志分析、数据看板

数据流转示意

用户请求 → Redis 缓存命中?
  ├── 是 → 直接返回(< 1ms)
  └── 否 → MongoDB 查询 → 写入 Redis 缓存 → 返回
                ↓
           异步同步到 ES(用于搜索)
# 混合架构示例:商品详情查询
import json

def get_product(product_id: str) -> dict:
    """三级查询:Redis → MongoDB → 返回并缓存"""

    # 第 1 级:查 Redis 缓存
    cache_key = f"product:{product_id}"
    cached = r.get(cache_key)
    if cached:
        print("✅ Redis 缓存命中")
        return json.loads(cached)

    # 第 2 级:查 MongoDB
    product = db["products"].find_one({"_id": product_id})
    if not product:
        return None

    product["_id"] = str(product["_id"])

    # 写入 Redis,TTL 5 分钟
    r.setex(cache_key, 300, json.dumps(product, ensure_ascii=False))
    print("📦 MongoDB 查询完成,已写入缓存")

    return product

场景 5:云上部署成本对比

以腾讯云为例,同等 4C8G 配置的月费:

服务腾讯云产品月费(按量/包年包月)
MongoDB云数据库 MongoDB¥320 起
Redis云数据库 Redis¥280 起
Elasticsearch云搜索服务 ES¥450 起
自建(CVM 4C8G)云服务器 CVM¥180 起

自建 vs 托管怎么选?

对比项自建托管(云数据库)
运维成本高(备份、监控、升级全自己来)低(一键高可用、自动备份)
初始费用低(只付 CVM 钱)高(溢价 50%-100%)
可靠性取决于运维水平SLA 99.95%+
适合有运维能力的创业团队追求稳定的企业

我的建议:初期用自建快速验证,业务跑起来后迁移到托管,别让运维拖了业务后腿。

选型决策速查表

你的需求选谁
通用数据存储,字段经常变MongoDB
缓存、会话、排行榜、限流Redis
全文搜索、日志分析、数据看板Elasticsearch
存 JSON,偶尔按字段查MongoDB
延迟要求 < 1msRedis
中文搜索 + 聚合统计Elasticsearch
需要事务MongoDB 4.0+
时序数据 + 实时计算Redis(TimeSeries 模块)

小结

NoSQL 选型的核心逻辑就三句话:

  1. MongoDB — 数据结构复杂、查询灵活,选它不会错
  2. Redis — 追求极致性能、做缓存和实时计算,非它莫属
  3. Elasticsearch — 搜索和分析是刚需,别犹豫

真正的难题从来不是「选哪个」,而是「你到底要解决什么问题」。搞清楚需求,选型自然就清晰了。


👤 作者简介

一枚在大中原腹地(河南)卖公有云的从业者,主营腾讯云/阿里云/华为云,曾踩坑无数,现专注AI大模型应用落地。关注公众号「公有云cloud」,围观AI前沿动态~

博客:yunduancloud.icu