前言

面试中问“这些存储怎么选”时,不能只回答“MySQL 存关系数据、Redis 做缓存、ES 做搜索”。这种说法方向没错,但无法说明为什么,以及数据增长、查询变复杂、故障发生后系统是否还成立。

更可靠的比较方式是依次判断:数据之间有什么关系、一次查询要按什么条件找、是否要事务、单条记录多大、写入是随机还是按时间顺序、数据量增长后如何扩展。

本文比较的对象并不完全在同一层:OpenTSDB 建立在 HBase 之上,通常将时间序列写入 HBase;Elasticsearch/OpenSearch 是检索和分析引擎;Redis、Memcached 是内存存储;Prometheus 同时是监控采集、告警和时序查询系统;RocksDB 是嵌入式存储引擎。它们常常组合使用,而不是非此即彼。

因此,本文中的“数据库”是广义数据存储。面试回答时要先说明它在架构中的角色:权威事实源保存订单、账户和库存等可追责数据;派生存储保存搜索索引、报表明细、向量和指标,可由事实源或消息流重建;缓存只加速访问,失效后必须允许回源。角色边界比产品名称更重要。

一张总览表

这张表不是“数据库排行榜”,而是面试或实际选型时的第一轮排除工具。它覆盖本文介绍的所有常见产品;后文再按类别补充核心用途、适用场景和选型边界。产品很多时,先按“要解决什么数据问题”筛选,再进入对应章节深入比较。

阅读时从左到右看三件事:

  1. 核心定位:它在系统中通常承担权威事实、缓存加速、检索投影还是监控指标等哪一层职责。
  2. 数据模型和最擅长的访问方式:先根据真实查询判断是否匹配,例如“按订单号更新并保证扣库存正确”与“按关键词检索商品标题”是两类完全不同的问题。
  3. 不适合承担的职责:这一列不是说产品绝对不能使用,而是提示一旦将其作为主方案,通常会付出一致性、成本、性能或运维复杂度的代价,需要有明确理由和补偿方案。
类别 系统 核心定位 数据模型 最擅长的访问方式 不适合承担的职责
关系型 MySQL InnoDB 通用在线事务库 行、表、外键关系 主键/二级索引查询、短事务、强一致更新 大规模全文检索、海量时序明细
关系型 PostgreSQL 功能丰富的关系型数据库 行、表、JSONB、范围等丰富类型 复杂 SQL、事务、分析能力、扩展类型 将它当作无限横向扩容的 KV 存储
缓存 Redis 内存数据结构服务器 String、Hash、List、Set、ZSet、Stream 等 极低延迟读写、缓存、计数、排行榜、短状态 唯一持久化事实来源、超大数据集存储
文档 MongoDB 文档数据库 BSON 文档与集合 聚合文档读写、字段经常演进、嵌套对象查询 高度复杂跨实体事务的核心账务模型
宽列 HBase 分布式宽列存储 RowKey + 列族 + 列限定符 + 时间戳 海量数据按 RowKey 范围读写、稀疏宽表 任意字段筛选、跨行事务、低延迟多维分析
搜索 Elasticsearch 分布式检索与分析引擎 JSON 文档、倒排索引 全文搜索、筛选、聚合、排序、高亮 作为唯一订单/账务真相库
时序 OpenTSDB 基于 HBase 的时序数据库 指标 + 时间戳 + Tag 指标按时间范围查询、监控看板 高基数 Tag、复杂关系事务
关系型 Oracle Database 商业级关系型事务数据库 行、表、关系与丰富企业特性 核心交易、高可用、传统大型企业系统 低成本快速试错、轻量级本地嵌入
关系型 SQL Server Microsoft 生态关系数据库 行、表、关系 .NET 业务、报表和 Microsoft 数据平台 脱离 Microsoft 生态且极度追求低许可成本的场景
嵌入式 SQLite 嵌入式单文件关系数据库 本地文件中的表和索引 移动端、桌面端、IoT、本地元数据 多实例高并发集中写入的服务端系统
分布式 SQL TiDB 分布式 NewSQL / HTAP 数据库 分布式行存事务表与列存分析副本 MySQL 兼容、横向扩展事务数据和分析 规模不大却只为“分布式”引入复杂运维
分布式 SQL CockroachDB / YugabyteDB 多地域分布式 SQL 数据库 分布式关系表 跨可用区/跨地域强一致 SQL 对跨地域写延迟非常敏感的链路
缓存 Memcached 简单分布式内存 KV 缓存 Key-Value 纯对象缓存、降低读库压力 持久化、复杂数据结构、可靠消息处理
嵌入式 KV RocksDB 嵌入式 LSM KV 存储引擎 本地 Key-Value 流处理状态、服务本地存储 作为开箱即用的分布式数据库服务
宽列 Cassandra 去中心化宽列数据库 分区键 + 聚簇列的宽行 多机房高可用写入、按分区键读取 任意条件查询、复杂 Join 和强事务账务
云 KV/文档 DynamoDB 托管式分布式 KV/文档数据库 主键、文档、二级索引 AWS 云原生按键高吞吐访问 需要规避云厂商绑定或复杂临时分析查询
搜索 OpenSearch 开源搜索与分析引擎 JSON 文档、倒排索引 搜索、日志检索、聚合分析 唯一权威业务数据存储
列式分析 ClickHouse 列式 OLAP 分析数据库 列式表、分区和排序键 大范围扫描、报表、行为和日志分析 高频单行更新的在线交易
列式分析 Apache Druid 实时 OLAP 分析数据库 时间分区列式数据 实时看板、流式事件聚合 通用多表事务处理
列式分析 Apache Pinot 实时 OLAP 分析数据库 实时/离线列式段 Kafka 流式行为分析、低延迟聚合 在线订单更新和复杂事务
时序 InfluxDB 专用时序数据库 Measurement + Tag + Field + 时间戳 IoT、业务指标、时序查询 把高基数业务标识无限制写入 Tag
时序/监控 Prometheus 监控采集与查询时序库 指标 + Label + 时间戳 云原生监控、告警、短中期指标查询 业务明细、无限期海量原始指标留存
时序 VictoriaMetrics 高性能 Prometheus 时序存储 指标 + Label + 时间戳 大规模指标长期保存、PromQL 查询 需要复杂关系事务的数据模型
Neo4j 图数据库 节点、边、属性 知识图谱、反欺诈、多跳关系查询 大规模核心账务交易和纯时序分析
时序 TimescaleDB PostgreSQL 时序扩展 关系表 + 时间分区 Hypertable 既要 SQL/事务又要时序分区和聚合 极端高基数、超大规模监控指标而无容量规划
向量 Milvus 向量数据库 向量、标量元数据、ANN 索引 语义检索、RAG、相似内容召回 替代精确事务查询、权限校验和最终排序
时序 QuestDB 面向高吞吐写入的时序 SQL 数据库 时间序列列式表 行情、IoT、指标数据的快速写入和 SQL 查询 需要成熟跨地域事务与复杂企业治理的核心系统

例如电商商品系统通常不是在表中任选一个:商品价格、库存和上下架状态放在 MySQL 或 PostgreSQL 中作为权威数据;商品标题和属性被异步同步到 Elasticsearch 或 OpenSearch 供搜索;热点商品详情放 Redis 减少数据库压力;主机 CPU、接口延迟等指标进入 Prometheus、VictoriaMetrics 或 OpenTSDB;运营行为明细可以进入 ClickHouse 做大范围聚合。总览表的目的,是先让每类数据回到合适的位置,再讨论索引、分片、同步延迟和故障恢复等具体实现。

先按需求快速定位

大总览用于查产品边界,实际面试或设计评审可以先用下面的路径缩小范围,再回到具体产品比较:

首要需求 先看哪类产品 生产上必须追问的问题
扣库存、账户余额、订单状态必须正确 MySQL、PostgreSQL、Oracle、SQL Server;明确需要分布式 SQL 时再看 TiDB、CockroachDB、YugabyteDB 事务边界在哪里?条件更新、唯一约束、幂等键和失败补偿如何做?
热点详情、会话、计数、限流需要毫秒级甚至更低延迟 Redis、Memcached;服务内部状态可看 RocksDB 缓存失效如何回源?热 Key、大 Key、穿透和雪崩如何治理?
商品/内容对象字段经常变化,通常整体读取 MongoDB;AWS 托管按键访问可看 DynamoDB 文档边界是否覆盖主要读取?是否把本该拆开的无限增长数组塞进一个文档?
数十亿明细按业务键、时间前缀批量写入和范围读取 HBase、Cassandra RowKey 或分区键能否同时满足查询和写入均衡?热点与超大分区怎么办?
关键词搜索、筛选、高亮、搜索聚合 Elasticsearch、OpenSearch 谁是权威源?索引通过 CDC/消息如何重建、补偿和对账?
大范围扫描日志、行为或报表并做聚合 ClickHouse、Druid、Pinot 分区、排序键、明细保留和预聚合是否围绕高频报表?
按时间窗口看指标并告警 Prometheus、VictoriaMetrics、OpenTSDB、InfluxDB、TimescaleDB、QuestDB 标签基数、保留周期、降采样、迟到点和长期存储如何控制?
多跳关系、相似内容召回 Neo4j、Milvus 图遍历起点与深度是否受限?向量召回后的权限过滤和重排序由谁完成?

常见数据库科普与核心用途

先澄清一点:日常口中的“数据库”既包含事务数据库,也包含缓存、搜索引擎、时序库和分析型存储。它们解决的问题不同,不能只按 SQL/NoSQL 二分。

mindmap
  root((数据存储))
    在线交易
      MySQL
      PostgreSQL
      Oracle
      SQL Server
      TiDB
      CockroachDB
      YugabyteDB
    内存与缓存
      Redis
      Memcached
      RocksDB
    文档与宽列
      MongoDB
      HBase
      Cassandra
      DynamoDB
    搜索与分析
      Elasticsearch
      OpenSearch
      ClickHouse
      Druid
      Pinot
    时间序列
      OpenTSDB
      InfluxDB
      Prometheus
      VictoriaMetrics
      TimescaleDB
      QuestDB
    专用存储
      Neo4j
      SQLite
      Milvus

关系型与分布式 SQL 数据库

数据库 核心作用 常见场景 选型提醒
MySQL 通用 OLTP 事务库 电商订单、用户、支付、后台管理系统 先做索引、归档和读写分离;写入或容量到瓶颈后再考虑分库分表
PostgreSQL 企业级关系库和可扩展数据平台 复杂 SQL、GIS、JSONB、报表、规则数据 强在丰富类型、扩展和 SQL 表达力;要重视长事务、VACUUM 和大表维护
Oracle Database 高可靠商业关系数据库 核心金融、电信、传统大型企业系统 成熟的高可用、治理和商业支持,代价是许可、运维与迁移成本
SQL Server Microsoft 生态关系数据库 .NET 企业应用、报表、数据平台 与 Windows、AD、Power BI 等生态集成度高,注意许可与平台依赖
SQLite 嵌入式单文件关系数据库 移动端、桌面端、IoT、CLI 工具、本地元数据 无独立服务进程,部署简单;不适合高并发网络服务的集中写入
TiDB 分布式 HTAP / NewSQL 希望保留 MySQL 协议,同时横向扩展事务数据和分析能力 适合分布式扩展需求明确的场景;不能把分布式系统的网络、运维和事务成本当作免费收益
CockroachDB / YugabyteDB 分布式 SQL 多地域部署、跨可用区高可用 SQL 服务 强调一致性与多地域容灾;需评估跨地域延迟、事务冲突和 SQL 兼容性

OLTP 指高并发、短事务的在线交易处理,例如下单和扣款;HTAP 指同一份数据既做事务处理又支持接近实时分析。不要因为需要报表就把交易库直接替换成分析库,优先明确读写和分析链路的时效要求。

内存缓存与 KV 存储

数据库 核心作用 常见场景 选型提醒
Redis 丰富数据结构的内存存储 缓存、会话、排行榜、限流、分布式协调、Stream 关注热 Key、大 Key、过期策略和缓存一致性;通常不是唯一事实源
Memcached 简单分布式内存 KV 缓存 纯对象缓存、历史系统 模型简单、无复杂数据结构和持久化;新项目通常 Redis 更常见
RocksDB 嵌入式 LSM KV 引擎 流处理状态、嵌入式存储、服务本地状态 它是库而非独立数据库服务;写放大和 compaction 是主要运维/性能关注点

Redis 与 Memcached 的核心任务都是减轻后端压力、降低读取延迟。差异不应只回答“Redis 支持更多结构”,还要说明 Redis 可以承担计数、队列等数据结构操作,而 Memcached 更专注简单缓存;两者缓存失效后都应能从权威源重建。

文档、宽列与大规模 KV 数据库

数据库 核心作用 常见场景 选型提醒
MongoDB 面向文档的应用数据存储 内容详情、商品聚合信息、字段经常变化的业务对象 文档聚合边界要合理;跨大量文档事务会增加复杂度
HBase 基于 HDFS 的海量稀疏宽表 日志明细、用户画像、轨迹、历史流水 查询必须围绕 RowKey 设计;列族数量和热点 RowKey 要控制
Cassandra 去中心化宽列数据库 多机房高可用写入、按分区键访问的海量数据 一致性可调;分区键设计和避免超大分区是关键
DynamoDB 托管式分布式 KV/文档数据库 AWS 云原生应用、按主键高吞吐访问 容量模型、热分区、二级索引和供应商绑定需要提前评估

这类系统共同特点是:通常不提供关系型数据库那样任意字段 Join 和自由组合查询。建模前必须先列出最重要的查询,再设计文档主键、RowKey 或分区键。

搜索、分析与列式数据库

数据库 核心作用 常见场景 选型提醒
Elasticsearch / OpenSearch 全文检索、过滤、聚合、日志搜索 商品搜索、知识库、日志检索、运营筛选 是派生索引而非核心事实库;需要处理 mapping、分片、重建与同步延迟
ClickHouse 列式 OLAP 分析数据库 BI 报表、行为分析、日志分析、指标聚合 擅长大范围扫描和聚合,不适合频繁按主键更新单行的交易模型
Apache Druid 实时 OLAP 分析库 实时看板、广告/行为流分析 时间分区和预聚合能力强,需评估数据摄入与查询模型
Apache Pinot 面向实时分析的 OLAP 用户行为实时查询、运营大盘 常与 Kafka 配合,适合低延迟聚合查询,不是通用事务库

列式分析数据库与 MySQL 的区别在于读取方式:报表经常只读取少数指标列、扫描大量行并聚合,列式存储可减少无关列 IO 并提高压缩率;交易更新通常涉及一整行状态,行式事务库更自然。

时序数据库

数据库 核心作用 常见场景 选型提醒
OpenTSDB 建在 HBase 上的指标时序库 主机/应用监控、历史指标曲线 关注 Tag 基数和 HBase RowKey 热点
InfluxDB 专用时序数据库 IoT 传感器、业务指标、监控数据 使用 Tag 做索引、Field 存数值;高基数 Tag 仍会带来压力
Prometheus 监控采集与查询时序库 云原生服务监控、告警、Kubernetes 指标 拉取模型和本地存储适合监控;长期海量存储常接 Thanos、Mimir、VictoriaMetrics 等远端方案
VictoriaMetrics 高性能时序存储与 PromQL 生态 大规模 Prometheus 指标长期保存 重点评估写入基数、保留周期、告警查询和运维形态
TimescaleDB PostgreSQL 上的时序扩展 既需 PostgreSQL SQL/事务又有时序分区与聚合 适合团队已使用 PostgreSQL 的时序业务,仍需规划压缩、分区和保留策略
QuestDB 面向高吞吐写入的时序 SQL 数据库 市场行情、IoT、指标数据 适合时间序列写入与 SQL 查询,仍需评估生态、运维和高可用方案

时序数据的最大风险通常不是单点值数量,而是时间序列基数。例如将 user_id、完整 URL、请求 ID 作为标签,会让每种标签组合形成一条新序列,索引和内存开销迅速失控。

图数据库与专用数据库

数据库 核心作用 常见场景 选型提醒
Neo4j 图关系存储与图遍历 知识图谱、反欺诈关联、推荐关系、多跳路径查询 适合关系遍历,不替代大规模账务交易库
Milvus 向量数据库 语义检索、RAG、相似图片/文本搜索 向量召回不是最终业务过滤,通常要结合关系库元数据和重排序

向量数据库的核心用途是近似最近邻(ANN)召回,不应把它描述为“替代 Elasticsearch 或 MySQL”。实际 RAG/搜索链路通常是向量召回 + 关键词/元数据过滤 + 重排序 + 权限校验。

数据怎样落盘

物理存储决定了写入放大、更新成本和查询路径。下面的模型比产品名称更值得记住。

flowchart TD
    A[业务请求] --> B{数据和查询形态}
    B --> C[关系行与事务]
    B --> D[缓存或嵌入式 KV]
    B --> E[聚合 JSON 文档]
    B --> F[海量按键宽表]
    B --> G[全文检索或列式分析]
    B --> H[指标时间序列]
    B --> I[关系遍历或语义召回]
    C --> J[MySQL / PostgreSQL / Oracle / SQL Server]
    C --> K[TiDB / CockroachDB / YugabyteDB]
    D --> L[Redis / Memcached / RocksDB / SQLite]
    E --> M[MongoDB / DynamoDB]
    F --> N[HBase / Cassandra]
    G --> O[Elasticsearch / OpenSearch]
    G --> P[ClickHouse / Druid / Pinot]
    H --> Q[OpenTSDB / Prometheus / InfluxDB]
    H --> R[VictoriaMetrics / TimescaleDB / QuestDB]
    I --> S[Neo4j / Milvus]
系统 主要物理组织 更新一条数据时的关键特点
MySQL InnoDB 主键聚簇索引页保存整行,二级索引叶子保存二级键和主键 更新会写 redo、undo、binlog;更新二级索引字段还要维护二级索引
PostgreSQL Heap 表页存行版本;索引通常保存键值和 TID,再定位 Heap 行 UPDATE 常产生新行版本,旧版本由 VACUUM 清理;不是 InnoDB 聚簇表
Redis 数据常驻内存,按对象编码保存;RDB/AOF 用于恢复 单命令原子,避免大 Key 和长命令;持久化不是关系库事务的替代品
MongoDB BSON 文档存入 collection;WiredTiger 负责页、压缩与缓存 文档内嵌对象适合整体读写,频繁膨胀或跨文档更新需重新评估模型
HBase 表按 RowKey 字典序分 Region;列族最终形成 HFile,写入先到 WAL/MemStore 再刷盘 LSM 风格写路径适合高吞吐追加;读可能合并多个 HFile,依赖 compaction
Elasticsearch 文档写入 Lucene segment;segment 不可变,删除/更新通过新增版本和标记删除实现 写入先进入 buffer/translog,refresh 后才可搜索;大量更新会带来 segment 合并压力
OpenTSDB 将 metric、tag、时间戳编码为 HBase RowKey,数据点写入 HBase 列 高吞吐时间序列写入依赖合理 RowKey 与 Tag 基数控制
Oracle / SQL Server 页式行存关系表、事务日志和缓冲池;具体实现由各自商业引擎管理 适合以事务正确性和企业级高可用为优先级的核心业务,更新需同时维护日志与相关索引
SQLite 单个本地数据库文件,页式 B-tree、WAL 或回滚日志 部署零运维;同一时刻写入并发能力受单文件锁和本地磁盘限制
TiDB / CockroachDB / YugabyteDB 数据按分片保存于多个节点,副本通过共识协议复制;TiDB 还可将分析副本放入列存 TiFlash 一次写入会涉及网络复制和事务协调,换来容灾和横向扩展,也带来跨地域延迟和冲突成本
Memcached 内存 slab 分配器中的简单 Key-Value 对象 只做易失缓存,淘汰后必须能从权威数据源重建
RocksDB 本地 WAL + MemTable + SST 文件组成 LSM 树 顺序写入快;后台 compaction 会产生写放大和磁盘 IO 峰值
Cassandra / DynamoDB 数据按分区键分布到节点或托管分区;Cassandra 使用 LSM/SSTable,DynamoDB 屏蔽底层实现 分区键决定数据分布和吞吐上限,热点分区会先成为瓶颈
ClickHouse / Druid / Pinot 列式数据按分区和数据段落盘,列压缩后批量扫描;实时数据通常先进入内存段或增量段 追加、批量导入和聚合读取很强;ClickHouse 的更新/删除多经 mutation 和合并完成,Druid/Pinot 更常通过段替换、重摄入或压缩处理,不适合交易式逐行更新
InfluxDB / Prometheus / VictoriaMetrics / QuestDB 按时间切块或分区保存序列,配套标签索引、压缩和保留策略 写入主要是追加;标签组合和保留周期决定索引、磁盘与 compaction 压力
Neo4j 节点、关系和属性分别持久化,并维护关系邻接信息 多跳遍历可直接沿关系访问;不适合把所有高频交易明细都建成图
TimescaleDB PostgreSQL 表按时间自动拆成 Hypertable chunk 继承 PostgreSQL 的行版本和 WAL,同时通过分块、压缩管理时序数据
Milvus 向量字段、标量元数据和 ANN 索引分别持久化,索引构建常异步完成 写入后要经历索引构建或增量索引阶段;向量维度、索引参数直接影响容量和召回延迟

一个容易混淆的区别:MySQL 与 PostgreSQL

两者都是关系型数据库,但表的物理组织不同:InnoDB 通常以主键为聚簇索引,按主键查找可以直接在主键叶子页取整行;PostgreSQL 默认表是 Heap,B-tree 索引先拿到 TID,再去表页取行并做 MVCC 可见性判断。

这不是谁更好,而是不同实现。PostgreSQL 的 Index Only Scan 还需要可见性映射配合,才能真正不访问 Heap;InnoDB 的二级索引查询通常也要根据主键回到聚簇索引取整行。

索引类型与查询路径

“有没有索引”只是开始,更重要的是索引能否匹配你的查询谓词和排序方式。

系统 核心索引或加速结构 典型查询 关键限制
MySQL B+ 树主键/二级索引、联合索引、全文索引 WHERE 等值/范围、排序、覆盖索引 联合索引受最左前缀影响;索引过多拖慢写入
PostgreSQL B-tree、GIN、GiST、BRIN、Hash 等值/范围/排序,JSONB/数组,空间与范围类型 B-tree 默认最通用;GIN 查询强但写入、维护成本较高
Redis 不存在“二级索引”这一通用能力 通过 Key 精确定位,再用 Hash/ZSet 等结构操作 需要按访问模式设计 Key;复杂筛选不能靠遍历全库
MongoDB 单字段、复合、唯一、多键、文本、地理空间索引 文档字段过滤、排序、数组条件 每个索引消耗内存和写入成本;复合索引仍需匹配查询顺序
HBase RowKey 有序索引、Bloom Filter、Block Cache 单行 Get、RowKey 前缀/范围 Scan 原生没有任意列的通用二级索引;查询模式必须先设计 RowKey
Elasticsearch 倒排索引、BKD 树、Doc Values、词典与聚合结构 关键词检索、过滤、数值范围、聚合、排序 mapping 和分词器决定结果;深分页和高基数聚合成本高
OpenTSDB 基于 HBase RowKey 的时间范围扫描,常结合预聚合 某指标、指定 Tag、某段时间的曲线 Tag 不是关系库索引;高基数 Tag 会放大行数和查询扇出
Oracle / SQL Server / SQLite B-tree 为主,并提供组合、唯一、全文或特定类型索引 事务表等值、范围、排序查询 索引设计仍遵循查询谓词与选择性;额外索引会增加写放大
TiDB / CockroachDB / YugabyteDB 分布式主键/二级索引;二级索引通常也需要分布式回表 按主键或索引过滤的 SQL 索引命中不代表低延迟,跨 Region/分片读取与分布式事务仍有网络代价
Memcached / RocksDB Memcached 仅精确 Key;RocksDB 以有序 LSM Key 和 Bloom Filter 加速 Key 查找,RocksDB 支持 Key 范围迭代 Memcached 没有通用二级索引;RocksDB 需由应用维护访问维度
Cassandra / DynamoDB 分区键定位分区,聚簇列/Sort Key 定义分区内顺序;可建立受限二级索引 已知分区键后的范围读取 不能把二级索引当任意查询能力;首要目标是避免跨分区扇出
OpenSearch 与 Elasticsearch 相同,使用倒排索引、BKD、Doc Values 搜索、过滤、聚合 同样需要治理 mapping、分片与高基数聚合
ClickHouse / Druid / Pinot 排序键、主键稀疏索引、分区裁剪、位图/字典等列式加速结构 时间范围内筛选、扫描和聚合 不是行式 B+ 树点查模型;排序键和分区必须服务高频查询
InfluxDB / Prometheus / VictoriaMetrics / QuestDB 时间索引加标签/Label 索引,按时间窗口扫描 指标 + 标签过滤 + 时间范围聚合 标签基数失控会先耗尽索引和内存;不能将每个请求 ID 作为标签
Neo4j 节点属性索引、全文索引与关系邻接遍历 从起点进行多跳图查询 图遍历必须有明确起点和深度,超级节点会造成扇出爆炸
TimescaleDB PostgreSQL 索引加时间 chunk 裁剪 时间范围 SQL、按设备/租户过滤 每个 chunk 的索引与分区数都要受控
Milvus IVF、HNSW、DiskANN 等 ANN 向量索引,配合标量过滤 Top-K 相似向量召回 近似召回存在精度、内存和延迟权衡,不能代替精确过滤和重排序

各自怎样“查一条数据”

  1. MySQL:二级索引命中后,通常通过主键回到聚簇索引取整行;覆盖索引可减少回表。
  2. PostgreSQL:B-tree 叶子项给出 TID,执行器访问 Heap 页并做 MVCC 可见性判断;合适时可走 Index Only Scan
  3. Redis:用精确 Key 做 GETHGETZSCORE 等,时间复杂度很低;不要用 KEYS * 或未知规模的 HGETALL 做查询。
  4. MongoDB:用索引定位 BSON 文档;若查询字段和返回字段均可由索引提供,可使用覆盖查询。
  5. HBase:最优路径是已知完整 RowKey 的 Get,其次是连续 RowKey 范围 Scan;按非 RowKey 字段查会变成全表扫描或需要额外索引表。
  6. Elasticsearch:查询词经分析后到倒排表找到候选文档,再经过过滤、打分、排序和聚合;它不是逐行扫描 JSON。
  7. OpenTSDB:根据指标、Tag 和时间范围构造或筛选一批 HBase RowKey,再读取数据点并按需要聚合下采样。
  8. Oracle、SQL Server、SQLite:优化器依据统计信息选择 B-tree 等访问路径;前两者通常服务端执行 SQL,SQLite 则在进程内直接访问数据库文件。
  9. TiDB、CockroachDB、YugabyteDB:协调节点将 SQL 拆为分布式执行计划,向存有目标分片的节点发起读取;按主键命中单分片最稳定,跨分片 Join/聚合需要交换数据。
  10. Memcached、RocksDB、Cassandra、DynamoDB:先由 Key 或分区键路由到目标节点/本地文件,再用分区内排序键或 Value 返回结果;缺少分区键的查询往往意味着扫描或额外索引。
  11. ClickHouse、Druid、Pinot:先通过时间分区和排序键排除无关数据段,再只读取参与过滤和聚合的列;这正是它们适合报表、不适合逐行交易更新的原因。
  12. InfluxDB、Prometheus、VictoriaMetrics、QuestDB、TimescaleDB:先按指标名和标签定位时间序列或时间分区,再在时间窗口内解压、下采样和聚合。
  13. Neo4j:先用属性索引找到起始节点,再沿关系边按指定方向和深度遍历;Milvus 则在向量索引中做 Top-K 近似近邻召回,然后由业务元数据过滤和重排序。

事务、一致性与可见性

系统 原子性与事务能力 一致性设计重点
MySQL InnoDB 完整 ACID,行锁、MVCC、redo/undo/binlog 订单、支付、库存等核心状态用短事务、唯一约束和条件更新兜底
PostgreSQL 完整 ACID,MVCC、WAL、丰富隔离语义 默认读写并发好;长事务会拖住旧版本回收,需监控 VACUUM 与事务年龄
Redis 单条命令原子;MULTI/EXEC、Lua 可组合原子操作 缓存一致性、锁超时、故障切换都要由业务补足;不能假设每次复制都零丢失
MongoDB 单文档原子;支持多文档事务但有成本 优先用文档聚合边界降低事务需求;多文档事务不是默认建模方式
HBase 单行原子;提供 Check-and-Mutate 等条件操作 不提供关系库式多行事务;通过 RowKey 设计、幂等写和异步补偿保证业务正确性
Elasticsearch 单文档写入与乐观并发控制;近实时搜索 写入成功到可搜索有 refresh 延迟;主库数据与 ES 索引应通过消息/CDC 和重试补偿同步
OpenTSDB 底层依赖 HBase 的单行语义 监控指标通常接受最终到达和补点;告警需要处理迟到数据与查询窗口
Oracle / SQL Server / SQLite 提供 ACID 事务与日志恢复;SQLite 更适合单机嵌入式事务 核心约束、事务边界和连接并发模型仍需按业务设计,不能因为是关系库就省略幂等与重试
TiDB / CockroachDB / YugabyteDB 提供分布式 ACID 事务和一致性副本 跨分片/跨地域事务的延迟与冲突更高;应让强事务尽量收敛到同一业务键或地域
Memcached / RocksDB Memcached 不提供事务和持久化保证;RocksDB 提供本地原子写批和 WAL 两者都不能替代分布式业务事务;RocksDB 的一致性边界只在单机实例内
Cassandra / DynamoDB Cassandra 提供可调一致性,DynamoDB 提供条件写和事务 API 用条件写、幂等键和分区设计保护正确性;不要假设跨分区操作天然低成本
OpenSearch 单文档乐观并发、近实时可见 与 Elasticsearch 一样应把它当派生搜索索引,通过 CDC、重放和对账恢复
ClickHouse / Druid / Pinot 主要面向分析摄入与查询,不是通用多行 ACID 事务库 明细通常来自 Kafka/对象存储/主库,需容忍重复并用事件 ID 去重或离线校正
InfluxDB / Prometheus / VictoriaMetrics / QuestDB 重点是时序写入和最终查询一致性,不承担业务事务 告警、聚合要处理迟到点、重复点和采集失败;权威业务状态仍应在事务库
Neo4j / TimescaleDB Neo4j 支持图事务;TimescaleDB 继承 PostgreSQL ACID 图更新或时序业务事务可以使用,但要控制长事务和跨大量数据分区的修改
Milvus 面向向量数据的插入、删除和索引构建,不是交易事务系统 向量库只保存检索副本或知识数据,原始文档、权限和版本仍需由权威库维护

一个常见架构误区是把 Elasticsearch 或 Redis 当成订单状态的唯一真相来源。更稳妥的方式是:关系库保存权威交易数据,事务提交后用 Outbox、Binlog/CDC 或可靠消息驱动缓存和检索索引更新;消费者必须幂等,并支持重放和校验。

扩展方式与容量边界

系统 主要扩展方式 最先出现的瓶颈 常见治理
MySQL 读写分离、分库分表、分区、归档 单主写入、单表索引和存储容量 优化 SQL/索引后再分片;以业务键设计路由
PostgreSQL 读副本、分区、逻辑复制、分片方案/扩展 单实例写入与大表维护 分区、归档、读扩展;跨分片查询成本要提前评估
Redis Cluster 分 slot、主从副本、本地缓存 单节点内存、热 Key、大 Key、网络 拆 Key、限制 Value、热点多级缓存、合理淘汰策略
MongoDB Sharding、Replica Set 分片键倾斜、跨分片查询、chunk 迁移 选择高基数且分布均匀的 shard key,避免单调递增热点
HBase Region 自动切分和分布式 RegionServer 热 RowKey、compaction、Region 倾斜 RowKey 加盐/分桶、预分区、列族控制、容量规划
Elasticsearch 主分片 + 副本分片横向扩展 分片过多、聚合内存、热点分片、segment 合并 按索引生命周期管理,控制分片数,冷热分层和 rollover
OpenTSDB 跟随 HBase 扩展 Tag 高基数、时间序列爆炸、热点写入 规范 Tag,避免用户 ID 等无界维度,预聚合和保留策略
Oracle / SQL Server / SQLite Oracle/SQL Server 以高配单机、读副本、分区和成熟 HA 为主;SQLite 通常单机随应用发布 商业许可、单实例写入或单文件并发写入 核心库优先做容量、备份演练和读扩展;SQLite 超出单机边界时迁移到服务端数据库
TiDB / CockroachDB / YugabyteDB 增加计算/存储节点并自动或半自动重均衡分片 热点范围、跨地域复制延迟、分布式事务冲突 以高基数主键分散写入,规划副本地域,监控重平衡、热点和事务重试
Memcached / RocksDB Memcached 客户端一致性哈希扩容;RocksDB 通过应用分片或上层系统扩展 Memcached 内存淘汰;RocksDB compaction、磁盘和单机容量 缓存可丢失可重建;RocksDB 管理好写缓冲、SST 和磁盘余量
Cassandra / DynamoDB Cassandra 增加节点并按 token 分布;DynamoDB 按托管分区自动扩缩 热分区、超大分区、二级索引放大 设计均匀分区键,拆分宽分区,限流并监控分区级吞吐
OpenSearch 与 Elasticsearch 相同,通过主分片和副本扩展 分片、堆内存、聚合和写入合并 采用生命周期、冷热分层和合理分片规格
ClickHouse / Druid / Pinot 按分片、时间分区和副本扩展计算与存储 数据倾斜、查询并发、后台合并和实时摄入积压 按时间/租户分区,预聚合常用指标,隔离重查询和实时写入资源
InfluxDB / Prometheus / VictoriaMetrics / QuestDB / TimescaleDB 通过时间分区、保留策略、远端存储或集群形态扩展 高基数、长期保留、压缩合并、告警查询峰值 禁止无界标签,降采样,分层保留;Prometheus 长期存储使用远端方案
Neo4j / Milvus Neo4j 需按版本/架构规划集群或分图;Milvus 可拆分计算、索引和对象存储 Neo4j 超级节点和图扇出;Milvus 向量维度、索引内存和重建 约束图遍历深度,按业务拆图;为 Milvus 选择 ANN 索引并预留重建与扩容容量

HBase 与 OpenTSDB 的特殊约束

HBase 不是“能装很多数据的 MySQL”。它要求先设计 RowKey,再写查询:例如按 tenant + metric + time bucket + hash bucket 组织数据,才能让同一类数据既能范围扫描,又不把所有写入打到同一个 Region。

OpenTSDB 也不是“给任意业务表加一个时间字段”。指标 cpu.usagehostregion 等 Tag 应该是有限、可控的维度。把 request_id、用户 ID、随机 URL 参数当 Tag 会制造海量时间序列,导致 HBase 行数、索引/元数据和查询扇出失控。

典型生产架构:不是选一个,而是明确数据主从关系

以电商商品搜索为例,比较合理的数据流如下:

flowchart LR
    A[商品后台] --> B[(MySQL / PostgreSQL: 权威商品与库存)]
    B --> C[Outbox 或 Binlog CDC]
    C --> D[消息队列]
    D --> E[(Elasticsearch: 检索索引)]
    D --> F[(Redis: 商品详情和热点缓存)]
    G[用户搜索] --> E
    H[商品详情] --> F
    F -->|未命中| B
    I[监控采集] --> J[OpenTSDB on HBase]

这个架构里,MySQL/PostgreSQL 是商品事实数据的权威源;Redis 是可失效、可重建的加速层;Elasticsearch 是可重建的检索投影;OpenTSDB/HBase 存放监控时序数据。每一层都要有重试、幂等和重建能力,不能只依赖一次消息投递成功。

面试选型回答模板

遇到选型题,可以按下面顺序作答:

  1. 先给数据定性:是交易事实、聚合文档、缓存状态、搜索索引还是时序指标。
  2. 说明主查询路径:按主键查、复杂 Join、全文检索、时间范围扫,还是排行榜/计数。
  3. 说明一致性边界:是否需要多行事务、能否接受秒级最终一致、是否允许丢失缓存。
  4. 说明增长方式:数据量、QPS、写入是否热点、是否需要水平扩展。
  5. 最后给出组合方案和故障补偿,而不是把某个中间件说成万能数据库。

可以用一句话收束:

MySQL、PostgreSQL、Oracle、SQL Server 适合需要事务的权威业务数据,SQLite 适合嵌入式本地数据;TiDB、CockroachDB、YugabyteDB 用于有明确横向扩展或多地域一致性需求的 SQL 场景。Redis、Memcached 是低延迟缓存,RocksDB 是嵌入式 KV 引擎;MongoDB 适合聚合文档,HBase、Cassandra、DynamoDB 适合围绕键或分区键访问的海量数据。Elasticsearch、OpenSearch 做搜索,ClickHouse、Druid、Pinot 做列式分析;OpenTSDB、InfluxDB、Prometheus、VictoriaMetrics、QuestDB、TimescaleDB 处理时序;Neo4j 做关系遍历,Milvus 做向量召回。真正的选型依据是数据模型、查询路径、一致性和增长方式,而不是产品热度。

高频面试题

MySQL、Redis、Elasticsearch 能互相替代吗?

不能。MySQL 是需要事务、约束和权威写入的业务主库;Redis 用于低延迟、可失效且可重建的数据访问;Elasticsearch 面向全文检索和聚合分析。生产中通常以 MySQL 或 PostgreSQL 为权威数据源,再通过 CDC、Outbox 或消息队列把数据同步到缓存和搜索索引。把订单事实直接只写入 Redis 或 Elasticsearch,会失去可靠事务、约束校验和可审计的恢复基础。

做数据库选型时,最先看哪些条件?

先确定数据模型和主查询路径:是主键点查、多表事务、文档聚合、全文检索、时序范围查询,还是大规模列式分析;再确认一致性边界、读写比例、数据量增长和热点分布;最后评估团队运维能力、备份恢复目标与成本。产品热度或单项压测 QPS 不能替代这些约束的判断。

为什么 Elasticsearch 不适合作为订单主库?

它的索引更新和分片复制更适合检索投影,而不是订单创建、扣库存、支付状态变更这类强事务流程。订单系统需要唯一约束、原子事务、明确的并发更新语义和可追溯的权威记录;Elasticsearch 的刷新可见性、文档更新冲突和索引重建成本会放大这些风险。合理做法是主库保存订单事实,ES 提供订单列表搜索和运营查询。

关系型数据库何时分库分表,何时考虑分布式 SQL?

先通过索引、分区、归档、读写分离和容量治理解决单库问题。当单表或单实例写入、存储、连接数已成为持续瓶颈,且业务可以按租户、用户或订单维度稳定路由时,分库分表通常更可控。若业务确实需要跨分片事务、全局 SQL 能力或多地域一致性,并能接受更高的延迟、运维和事务冲突成本,才评估 TiDB、CockroachDB、YugabyteDB 等分布式 SQL。

时序数据库和列式分析数据库如何区分?

时序数据库围绕时间窗口写入、标签过滤、保留策略和降采样设计,适合监控指标、设备遥测和告警;列式分析数据库围绕大范围扫描、分组聚合和报表分析优化,适合日志明细、经营分析和 OLAP 查询。两者都能按时间存储,但指标告警不能只靠离线 OLAP,复杂明细分析也不应全部压到监控时序库。

缓存、搜索索引和主库之间的一致性如何保证?

主库提交事务后,通过 Outbox 或 Binlog CDC 可靠地产生变更事件,再由消费者更新 Redis 和 Elasticsearch。消费者必须幂等、可重试并能处理乱序;缓存要设置合理 TTL,并在更新时删除或更新对应 Key;索引和缓存必须可全量重建。监控同步延迟、消费积压、失败死信和主库与派生数据的抽样差异,避免把一次消息发送成功误判为数据已经一致。

总结

没有一种数据库能同时以最低成本完成交易、缓存、全文检索、列式分析、海量宽表、时序分析、图遍历和向量召回。生产系统的关键是分清权威数据、派生数据和缓存数据:权威数据以事务和约束保证正确性,派生数据可以通过异步同步与重建保证最终一致,缓存数据必须允许失效和降级。新增数据库也应按这个边界组合使用,而不是因为某个产品支持多种能力就让它承担全部职责。