FEATURED · 精选文章

数据仓库不是更大的数据库:从OLTP到OLAP的架构解析与实践

发布时间 / 2026/9/9 22:40:43
来源 / 创域科博编辑部
栏目 / 资讯中心
数据仓库不是更大的数据库:从OLTP到OLAP的架构解析与实践 1. 先回答一个几乎所有人都会问的问题数据仓库到底是不是一种“更大的数据库”如果有人问我数据仓库和数据库的区别我通常不会直接甩定义而是先反问一句你最近一次用数据库是查一条订单还是统计一万个订单这个问题很关键。因为绝大多数人对数据仓库的误解就是从“它大概是数据库的升级版”开始的。实际上数据仓库不是更庞大的数据库也不是数据库的替代品它和数据库是两种在不同的年代、为解决不同问题而诞生的东西。数据库解决的是“业务能不能跑得动”数据仓库解决的是“数据能不能用得好”。我第一次接触数据仓库时也犯过这个错误。当时公司要做一个报表平台业务方张口就要“把订单表、用户表、商品表都同步过去然后随便查”。我就想这不就是一个只读数据库吗后来才发现如果只是把数据复制一份玩不出什么花。真正的数据仓库从数据模型、存储方式、查询引擎到调度策略都和联机事务处理OLTP数据库有本质差异。1.1 为什么会有数据仓库这个东西要理解数据仓库得先理解它的诞生背景。上世纪80年代末、90年代初企业已经用数据库跑业务很多年了。财务系统、库存系统、CRM系统都在生产环境稳定运行。但问题来了领导想看“本月各区域销售对比”DBA要从订单库里写一条SQL关联七八张表跑上半小时然后数据库CPU直接被打满前台业务卡死。业务部门抱怨报表慢DBA抱怨查询影响生产IT部门每天救火。于是大家意识到面向事务处理的数据库它的表结构设计、索引机制、锁策略都是为了让“快速写入单条数据、修改单条数据、查询单条数据”更高效而不是为了让“几百亿条记录做聚合分析”更高效。两者对系统的要求完全相反。数据仓库就是在这个背景下被提出的把分析型负载从生产库中剥离出来专门构建一套面向分析的数据存储和处理体系。这套体系的设计原则用一句话概括就是面向主题、集成、非易失、随时间变化。简单解释一下面向主题数据按业务主题组织比如“销售”“客户”“库存”而不是按业务系统的功能模块。集成来自不同源系统的数据要统一编码、统一单位、统一口径比如A系统叫customer_idB系统叫cust_no到了数仓里必须变成一个字段。非易失数仓里的数据基本只追加、不修改记录的是历史状态不是当前业务账。随时间变化数据仓库天然带着时间维度你能回答“上季度和这季度比改变了什么”而不是只看当前值。这四个特性决定了数据仓库的建模方式、存储结构、ETL流程都和传统数据库不同。1.2 数据仓库和数据库从“设计初衷”就不一样我从一开始就强调一个观点不要把数据仓库当成“数据库的进阶”它恰恰是数据库在另一个方向上的演进。传统的OLTP数据库设计目标是保证ACID原子性、一致性、隔离性、持久性核心关注点是事务处理。你去银行转账账户扣款和收款方入账必须是一个原子操作不能扣了钱对方没收到。这种场景要求数据库有很强的约束、索引、行级锁大量使用范式化设计来避免数据冗余和更新异常。数据仓库则完全反过来。它的核心关注点是分析查询的吞吐量是“一条复杂SQL能不能在几秒内扫描完几十亿行数据”。它不关心单条记录的实时更新更关心批量装载、列式存储、并行计算、分区裁剪。所以你会看到两个典型的差异数据库里一张订单表可能拆成订单头表、订单明细表、客户表、商品表通过外键关联这叫范式化。数仓里则更喜欢把核心维度打平成大宽表牺牲存储换速度这叫反范式化。数据库的索引是B树为主适合精确查找。数仓的索引更多是分区、桶、位图索引配合列式存储适合范围扫描和聚合。我在和很多开发同学聊天时发现最容易踩的坑就是用写业务系统的思路去建设数仓。比如一上来就建三范式模型把所有维度拆得干干净净结果分析报表要关联十几张表性能惨不忍睹。反过来说如果把生产库设计成大宽表业务写入的更新异常会让你痛不欲生。这两种体系各自有各自的土壤。2. 从一张订单表看OLTP和OLAP在行为上的天壤之别要真正搞懂数据仓库不能只停留在概念上。我习惯用一张订单表来举例因为它几乎是所有业务系统里最核心、最常见的一张表也是OLTP和OLAP差异最直观的载体。假设你的业务系统有一张订单表字段说明order_id订单ID主键user_id用户IDproduct_id商品IDorder_amount订单金额order_time下单时间status订单状态province收货省份2.1 数据库是给业务系统“跑交易”的这套系统在线上跑的时候用户每下一单程序就执行一条INSERT INTO orders ...然后给用户返回“下单成功”。有时候同时有上千人下单数据库要保证互不干扰每条订单都能快速写入。后台管理中客服要根据订单号查订单详情用SELECT * FROM orders WHERE order_id 123456主键命中毫秒级返回。这种场景还有一个特点数据量虽然不断增长但单次操作的数据量极小重要的是并发能力和响应速度。数据库每次操作只需要访问几行数据索引能非常高效地工作。这就是典型的OLTP联机事务处理负载。如果用数据库去做“某个月份某省份订单总金额”这种统计也不是不能跑但代价很高。因为订单表可能已经有几千万行而索引对聚合查询的帮助很有限。哪怕你建了(order_time, province)联合索引数据库也还是要扫描一段时间窗口内的所有行然后逐行累加。这个过程会占用大量I/O和CPU而且统计的时间段越宽性能越差。更麻烦的是这种慢查询会和其他事务抢资源直接影响线上体验。2.2 数据仓库是给分析场景“算总账”的现在看数据仓库怎么处理同样的表。数仓会先把这张订单表按天分区、按省份分桶用列式存储落到分布式节点上。同样一个统计需求“今年上半年每个省的订单总量和总金额”在数仓里执行时会触发分区裁剪只读1月到6月的数据然后走列式存储只读取province和order_amount两列其他字段碰都不碰再配合MPP大规模并行处理引擎把数据拆到多个节点并行累加。结果就是哪怕原始数据量已经达到几十亿行这个统计也往往能在几秒内完成。这就是OLAP联机分析处理的核心特征单次查询涉及的数据量很大但查询频率远低于OLTP而且几乎不涉及单条记录级别的修改。它要的是吞吐量不是事务性。2.3 用一张对比表梳理核心差异我把数据仓库和数据库的关键差异整理成一个表格方便你对照着理解对比维度数据库OLTP数据仓库OLAP核心目的支撑业务事务处理支撑分析决策典型操作增删改查单条记录批量读取、聚合分析数据量级一般从几万到几千万行部分可达亿级从几千万到几十亿、上百亿行起步数据模型范式化设计为主维度建模、宽表、反范式化存储方式行式存储为主列式存储为主索引策略B树、唯一约束分区、分桶、位图索引、排序键实时性要求毫秒级读写允许秒级到分钟级延迟批量更新并发特征高并发小查询低并发大查询数据变化频繁更新、删除以追加为主历史不可变典型产品MySQL、Oracle、PostgreSQL、达梦、人大金仓Hive、ClickHouse、Doris、Greenplum、Snowflake表格不是让你背的而是帮你建立两个画面。画面一数据库就像超市收银台每笔交易要快速结算排队的人很多画面二数据仓库就像后台财务室定期把一天的账本拉出来算利润、做同比、拆细项。你能要求收银台同时兼做财务分析室吗理论上有这种小超市但业务规模一大必然要分开。3. 数据仓库内部到底长什么样分层架构是它的灵魂理解完区别接下来要进入实战了。数据仓库之所以叫“仓库”是因为它内部有一套非常明确的组织逻辑。这套逻辑的第一体现就是分层。很多刚接触数仓的人最常问的就是数据仓库分层4层叫啥标准答案是ODS、DWD、DWS、ADS有时还会加一层DIM维度层。我在真实项目里见过五层、六层的设计但万变不离其宗核心就是这四层。3.1 经典四层ODS、DWD、DWS、ADS把这四层拆开讲ODS层操作数据存储层这一层是最贴近源系统的简单说就是“原样落地”。你把业务库里的数据通过同步工具比如DataX、Kettle、Flink CDC抽到数仓几乎不做清洗转换只是在源数据基础上加上一个日期分区按天存储。ODS的目的很简单先把数据拿过来别影响源系统同时也是后续所有加工的数据原材料。DWD层明细数据层这一层是数据清洗和标准化的关键环节。你需要统一字段命名、统一枚举值、统一时间格式比如把sex1/0转成male/female把created_at和create_time统一成create_time。同时会做一定的维度退化把一些常用维度字段直接冗余到明细表方便下游使用。DWD层保存的是经过清洗后的、最细粒度的业务事实它是一张大明细宽表。DWS层汇总数据层这一层也叫服务层核心是“按主题做汇总”。比如你按“当天”“省份”“商品类目”统计订单金额和订单量把结果预聚合到一张表里。为什么需要这一层因为直接查DWD层的十几亿行明细做报表查询压力还是很大。DWS层相当于把一些高频率使用的统计口径提前算好下游只要按照汇总粒度查表秒级出结果。ADS层应用数据层ADS层就是给具体应用用的面向BI报表、大屏、数据产品。它的数据通常是高度定制化的一张表可能就对应一个页面。比如“经营驾驶舱”里展示的月度销售趋势、品类排行都是ADS层直接提供的。这一层的数据量不大但查询频率高对稳定性要求很高。3.2 为什么必须分层直接一层不行吗我在小公司见过“一张表打天下”的猛人业务库同步过来后写一个超级复杂的SQL直接算所有指标给报表。前期确实爽数据量一上来就崩了。原因不难理解第一分层是“缓存思想”的体现。ODS只要同步DWD只要清洗DWS预计算ADS只输出每一层都在为上一层减负。好比做饭买菜ODS、洗菜切菜DWD、配菜调味DWS、上桌装盘ADS如果从买菜到上桌只有一步那厨房就全乱了。第二分层能实现口径统一。没有分层时A报表统计“活跃用户”是一种SQL写法B报表统计“活跃用户”又是另一种写法两个数字对不上业务部门天天扯皮。有了DWS层预先定义的指标口径所有下游都从同一张汇总表取数数字自然一致。第三分层便于权限控制和故障隔离。ODS层只允许ETL同学访问DWS层可以开放给数据分析师ADS层可以提供给产品经理看板。某一层挂了不至于影响上层全部应用至少能保证历史数据查询正常。有些朋友问那我不建数仓直接用ClickHouse把明细表拉来分析行不行可以但你要清楚ClickHouse本身不是完整的数据仓库体系它更接近OLAP引擎。分层建设不是数仓的唯一答案而是目前在大规模数据分析场景下最成熟、最容易维护的工程模式。3.3 我见过的最容易搞混的“维度建模”和“范式建模”说到分层就必须提建模。很多人在这一块很混乱动不动就“反范式”“星型模型”一阵背。数据库建模最常用的是三范式目的是消除冗余、避免更新异常。但数仓里更常用的是维度建模核心是事实表和维度表。事实表记录业务发生的过程每行是一个测量事件比如一笔订单、一次点击、一次登录。事实表里一般只有外键和度量值金额、数量、时长。维度表描述业务环境的属性比如用户维度、商品维度、门店维度。维度表提供上下文回答“谁、什么、在哪、何时”这些问题。用订单分析举例产生一笔订单后订单事实表记录user_id、product_id、order_time、amount。而用户维度表记录这个用户的性别、年龄、城市商品维度表记录商品名称、类目、价格。分析时要看“一线城市的女性用户最爱买什么”只需要把事实表和这两张维度表关联起来按维度分组聚合。这就是最经典的星型模型中间一张事实表周围若干张维度表就像星星一样。如果维度表之间还继续拆分比如把地址维度拆成省、市、区等多张表就形成雪花模型。雪花模型更规范但查询关联更复杂星型模型简单直观在数仓里是主流选择。4. 数据仓库落地过程中的选型与实战经验理论说了一堆但真正让数据仓库从“PPT架构”变成“可运行系统”的是选型、建模、调优这三件事。我在这部分会讲一些比较实战的东西这些东西都是我踩过坑以后总结出来的。4.1 到底选MPP数据库还是Hadoop体系很多人一上来就问数仓到底用什么工具是Oracle、MySQL还是Hive、ClickHouse、Doris这个问题没有标准答案因为不同团队的数据量、预算、技术栈都不一样。先厘清一个概念数据仓库和数据库引擎不是一回事。数据仓库是一套数据组织方法它可以构建在多种底层引擎上。你可以在Hive上建数仓也可以在ClickHouse上建数仓甚至可以在Greenplum、Doris、StarRocks这些分布式数据库上建数仓。我们做选型时一般会画一条分界线数据量在TB级别以内、实时性要求高、团队规模小优先考虑MPP数据库比如Doris、StarRocks、ClickHouse、Greenplum。它们部署简单、查询性能强支持标准SQL从MySQL/Oracle迁过来成本低。数据量在几十TB甚至PB级、有复杂ETL和大量离线批处理需求偏向Hadoop生态Hive/Spark加上配合调度系统比如Airflow、DolphinScheduler。Hadoop生态的扩展性强生态丰富但运维复杂SQL延迟也更高。我个人的建议是不要为了技术新鲜感去选型。很多中小公司业务量撑不起Hadoop的运维成本硬上Hive只会让数仓变成“查询慢、任务每天挂、DBA天天加班”的灾难。用Doris或者ClickHouse做一个轻量级数仓往往幸福指数高很多。4.2 数仓建模从哪下手维度表、事实表、缓慢变化维选好引擎之后下一步是建模。我建议新手按这个顺序去实践第一梳理业务流程和指标。先搞明白业务方关心的指标有哪些是订单金额、下单用户数还是复购率。明确指标之后再反推需要哪些事实表和维度表。第二确定事实表的粒度。粒度就是“一行代表什么”。订单事实表每一行代表一个订单还是代表订单明细行这个必须一开始就定死否则后续统计会混淆。我见过很多案例因为粒度没定义清楚导致同一张表既统计订单数又统计商品件数结果口径全错。第三设计维度表和缓慢变化维。维度表相对好设计重点是处理维度属性变化。比如用户的“会员等级”从普通用户变成金牌用户这个变化对历史订单分析有没有影响如果我们要分析“下单时的用户等级”就不能直接覆盖原来的等级字段而应该使用缓慢变化维SCD策略。最简单的SCD策略是直接覆盖Type 1不保留历史适合对历史不敏感的字段。更常用的是新增一行并带上开始时间和结束时间Type 2这样既能还原当时的情况也能追踪历史变化。实际项目中不要每条维度都做Type 2因为会大大增加存储和ETL复杂度。只有那些真正影响业务分析的字段比如用户等级、门店状态才值得做。第四写ETL脚本实现数据从ODS到DWD、DWS、ADS的自动加工。ETL脚本尽量用SQL实现因为可读性强、调试方便。复杂逻辑可以用Spark/Flink写但要做好数据血缘和任务日志。4.3 数仓性能调优的几个常见坑这里列几个我实际碰到过的坑比较典型。第一个坑是列式存储却不指定排序键。ClickHouse和Doris这类引擎排序键决定了存储顺序和数据压缩比。如果不设计排序键查询过滤效果会很差。比如订单表经常按order_time和province过滤就应该把这俩字段作为排序键让相邻数据在磁盘上尽量连续查询时能跳过大量分区。第二个坑是使用SELECT *到处查。列式存储的强项是按列读取只查询需要的列能极大减少I/O。很多人写SQL懒直接SELECT *导致每查一次都要读全列性能下降好几倍。这一点在数仓里比在OLTP数据库里影响更明显。第三个坑是分区字段选错类型。有些同学把时间字段定义为字符串再用LIKE 2024-01%来做过滤分区裁剪直接失效全表扫描。正确的做法是用DATE或DATETIME类型用范围条件才能触发分区裁剪。第四个坑是关联查询时小表不在前面。虽然在MPP引擎里优化器会自己做谓词下推和join重排但如果你用Hive或者Spark关联顺序对性能影响还是很大。建议手动把维度表等小表放前面用MapJoin或Broadcast Join减少shuffle。这些坑看起来很细但在数仓性能问题里占比非常高。我调优过不少慢查询最终发现80%的问题都不是引擎不够强而是SQL写法或者表设计不符合引擎特性。5. 数据仓库和数据库的边界正在模糊但这不等于没区别近些年出了很多新概念湖仓一体、HTAP混合事务/分析处理、实时数据仓库、向量数据库。有些人开始说“数据仓库要过时了”“数据库和数仓的界限已经不存在了”。我的观点是边界确实模糊了但底层逻辑没变不能因为工具变强就否定架构设计的意义。5.1 湖仓一体、HTAP到底在解决什么问题先说HTAP。传统架构里OLTP数据库和OLAP数据仓库是分开的业务系统写MySQL通过ETL同步到数仓数仓跑分析。这套架构最大的痛点是时序性数据从生产到分析有T1延迟甚至更久。HTAP数据库想解决的就是这个痛点让一个系统同时提供事务处理和分析处理能力典型产品有TiDB、OceanBase等。它能在你执行事务性写入的同时对同一份数据做复杂的分析查询理论上不用再分OLTP和OLAP两套系统。那HTAP能不能完全替代数据仓库我的判断是能替代一部分但替代不了复杂数仓场景。原因很简单HTAP的定位是“实时业务分析”能处理的数据规模和复杂程度是有限的。当你需要做跨数月的超大规模历史数据回溯、需要整合十几个异构数据源、需要做复杂的多层ETL时仍然需要数据仓库这种体系化的分层架构。再说湖仓一体。数据湖以低成本存储海量原始数据包括结构化、半结构化、非结构化数据典型如Iceberg、Hudi、Delta Lake。数据仓库擅长处理结构化数据但面对日志文件、图片元数据、音频文件就力不从心。湖仓一体是把数据湖的灵活性和数据仓库的管理能力结合起来把数仓的“健壮的表结构约束”下沉到数据湖的文件上。所以你看HTAP和湖仓一体真正解决的问题是“实时性”和“多样性”没有推翻“事务和分析分离”的事实。数据仓库的本质仍然是面向分析、面向历史的这个定位不会边缘化。5.2 什么时候你该考虑上数据仓库很多同学问我公司才几百张表、几十G数据有必要搞数仓吗我的答案是不要盲目跟风。你现在可以拿这几个问题自测你是不是经常要跑超过10分钟的分析查询而且已经影响到业务库性能你是不是有多个业务系统同一个“用户ID”在A系统叫user_id在B系统叫uid每次取数都要人工对齐业务方是不是总抱怨“报表数据不准两个部门出来的订单数不一样”你是不是需要看历史变化趋势而源系统只保留最近三个月的数据如果以上答案全部是否那你可能连数仓都不需要老老实实用好数据库就行。如果中了2条以上说明你已经有分析负载和口径统一的诉求了可以考虑引入数仓。我建议的最小落地路径是先建一个ODS层把所有源系统数据按天同步到仓库里再建一张核心业务宽表相当于DWD层把常用的维度字段关联进去最后基于宽表做报表。等这一套跑顺了再逐步增加DWS汇总层、完善指标口径管理。不要一上来就照着大厂的“ODS-DWD-DWS-ADS”照搬规模不同复杂度对应也不同。5.3 给新人的一个最低成本入门路线如果你是个完全没接触过数仓的新人又想快速建立体感我建议按这个路线来操作第一步找一台电脑装一下MySQL或者PostgreSQL把一张十万行的订单表导入进去试着自己写聚合SQL比如按省份、按月统计订单金额。感受一下分析SQL在OLTP数据库上的性能瓶颈。第二步装一个开源的ClickHouse或者Doris用官方docker部署很省事把同一份数据导进去按天分区、按省份排序再跑同样的SQL对比一下性能差异。你会发现可能从几百毫秒变成几十毫秒这一下就理解了列式存储和OLAP引擎的威力。第三步手动模仿四层架构。建一个ODS表存原始数据再建一张DWD表清洗脏数据再建一张DWS表按天汇总最后从DWS查数据做Excel图表。不用任何工具用SQL就能完成全流程。做完这一步你对数仓的理解会超过很多只背概念的人。这个过程中你还会接触到“ETL”“调度”“元数据”“数据血缘”这些概念。先不用焦虑一个个在实际操作中去理解它们解决什么问题比堆术语有效得多。动手永远是学习数仓最好的方式。我在早期学习时就吃了只看书的亏看了半年理论遇到真实项目还是不知道怎么建表。后来自己搭了一套最小环境从同步数据到报表输出完整跑通之后很多疑虑一下子就通了。希望这篇文章能帮你减少一些摸索时间让你少走几步弯路。
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻