DB2摘要表是一种特殊的物理表,它存储的不是原始明细数据,而是一条查询语句的预计算结果。摘要表在早期版本中被称为Summary Table,后来官方术语更倾向于物化查询表(Materialized Query Table,MQT),但很多数据库管理员仍然习惯沿用摘要表这个名称。它与普通视图最大的区别在于:视图只保存SQL定义,每次访问视图时都会重新执行定义中的查询;而摘要表会把查询结果真正存储在表空间中,后续查询可以直接读取已经聚合好的数据,不需要重复计算。例如销售明细表有上亿行,如果业务经常按区域和月份统计销售额,创建一个按区域和月份分组的摘要表,查询成本会从全表扫描加哈希聚合降低为直接扫描几万行甚至更少的数据。

一、摘要表与普通表、视图的本质区别
要理解摘要表的用途,首先要分清它和普通表、视图之间的边界。普通表里的数据由应用程序通过INSERT、UPDATE、DELETE等方式写入,DB2不会关心这些数据是怎么来的,也不会自动维护数据与其它表之间的关系。视图则完全不同,它没有自己的存储空间,只是一个被保存的查询定义,每次引用视图时都要重新执行该查询。摘要表介于两者之间:它像普通表一样占用物理存储空间,但数据内容由一条SELECT语句定义,并通过刷新操作从源表重新生成。
DB2中的摘要表支持两种刷新模式:REFRESH IMMEDIATE和REFRESH DEFERRED。REFRESH IMMEDIATE表示当源表发生增删改时,摘要表会在同一事务内同步更新。这种模式听起来更省心,但限制很多,通常要求摘要表基于单表,并且不能包含GROUP BY、HAVING以及连接操作,因此真正用于聚合分析的摘要表大多采用REFRESH DEFERRED模式。REFRESH DEFERRED意味着源表数据变化后,摘要表不会自动同步,必须由DBA或调度任务手动执行REFRESH TABLE来完成数据重建。
另外,摘要表也不等同于索引。索引是依附于某张表的辅助结构,用于加速定位行,它不会改变查询本身的语义;而摘要表是一张独立的冗余表,优化器可以在满足条件时把整条查询改写为读取摘要表。索引不能替代聚合结果,摘要表则可以省去大量排序、分组和聚合运算。也正因为摘要表会占用额外存储并需要刷新维护,它更适合数据仓库、BI报表和决策支持系统,而不是频繁写入的OLTP环境。
二、创建DB2摘要表的完整语法与示例
在DB2中创建摘要表使用CREATE SUMMARY TABLE语句,完整的语法结构包含三个关键部分:第一是AS后面的完整SELECT语句,定义摘要表的数据来源和聚合逻辑;第二是刷新模式子句,决定数据何时更新;第三是ENABLE QUERY OPTIMIZATION,明确允许DB2优化器在查询重写时考虑这张摘要表。下面通过一个销售汇总场景来演示完整的创建过程。
CREATE TABLE sales_detail (
order_id BIGINT NOT NULL,
region VARCHAR(20),
product_id INTEGER,
sale_date DATE,
amount DECIMAL(15,2)
);
CREATE SUMMARY TABLE sales_region_summary AS
(
SELECT region,
product_id,
SUM(amount) AS total_amount,
COUNT(*) AS order_count
FROM sales_detail
GROUP BY region, product_id
)
DATA INITIALLY DEFERRED
REFRESH DEFERRED
ENABLE QUERY OPTIMIZATION;
上面语句中的DATA INITIALLY DEFERRED表示创建摘要表时不立即填充数据,随后需要手动执行刷新操作。REFRESH DEFERRED表示该摘要表采用延迟刷新模式,源表的数据变化不会自动同步到摘要表。ENABLE QUERY OPTIMIZATION是让优化器能够识别并使用这张摘要表的关键子句,如果缺少它,DB2只会把摘要表当作普通表使用,不会自动进行查询改写。
创建完成后,摘要表里还没有数据,需要执行REFRESH TABLE命令来填充。该命令会重新执行摘要表定义中的SELECT语句,并把结果写入摘要表。如果源表数据量很大,这个过程会消耗可观的CPU、I/O和日志资源,建议放在维护窗口执行。
REFRESH TABLE sales_region_summary;
刷新完成后,可以通过系统目录表SYSCAT.TABLES查看摘要表的类型和状态。例如查询表名、类型以及是否启用查询优化,以确认对象创建是否符合预期。日常运维中也可以定期检查这些信息,避免摘要表建完后一直处于空数据或未启用状态。
三、让优化器自动使用摘要表:CURRENT REFRESH AGE
很多项目在创建了摘要表之后,发现查询性能没有任何变化,原因往往是忽略了CURRENT REFRESH AGE这个特殊寄存器。对于REFRESH DEFERRED类型的摘要表,DB2默认情况下不会在查询重写中使用它,因为源表和摘要表之间的数据可能存在延迟。只有在当前刷新年龄允许范围内,优化器才认为摘要表的数据足够新鲜,可以安全地用于替代原始表。
要启用DEFERRED摘要表的自动匹配,需要在会话中执行下面的设置。CURRENT REFRESH AGE默认值是0,表示只允许使用没有数据延迟的对象。将其设置为ANY后,优化器不再关心摘要表是否已经过期,只要查询逻辑能够从摘要表推导出来,就可能使用它。
SET CURRENT REFRESH AGE = ANY;
设置完成后,再次执行原始的聚合查询。以销售明细表为例,业务端可能仍然按照原始数据表编写SQL,而不需要知道摘要表的存在。优化器收到这条查询后,会根据成本估算判断是扫描sales_detail做实时聚合,还是直接读取sales_region_summary。只要摘要表数据足够新,并且查询中的分组列、聚合列都能从摘要表获得,执行计划中就会出现摘要表的名字,查询时间也会显著下降。
SELECT region,
product_id,
SUM(amount) AS total_amount,
COUNT(*) AS order_count
FROM sales_detail
GROUP BY region, product_id;
需要注意的是,优化器匹配摘要表并不是简单的名称替换。它会检查查询的GROUP BY列是否与摘要表的定义一致,聚合函数是否能够对应,查询中的过滤条件是否只涉及摘要表中已有的列。如果摘要表没有包含某些维度列,而查询又需要按这些列过滤,优化器很可能无法直接使用摘要表,或者需要回到原始表做补偿计算。因此设计摘要表时,应该尽量让它的粒度与高频查询的维度保持一致,而不是把所有可能的列都塞进去。
从性能收益来看,原始sales_detail如果有几亿行,每次按region和product_id聚合可能需要扫描大量数据页并进行哈希分组。而汇总后的sales_region_summary可能只有几十万行,扫描成本降低到原来的几百分之一。对于报表系统、管理驾驶舱和多维分析场景,这种提升通常能把响应时间从几十秒压缩到秒级甚至亚秒级。
四、摘要表的刷新策略、限制与维护建议
REFRESH DEFERRED摘要表需要靠人工或调度任务刷新,因此刷新策略直接决定了数据的时效性。常见的做法是在ETL流程结束后执行REFRESH TABLE,这样当天的事实数据装载完成后,摘要表也会一起更新。如果业务对实时性要求较高,可以使用更短的刷新周期,但要注意刷新操作本身会消耗资源,并且可能阻塞正在读取摘要表的查询。对于数据量特别大的摘要表,可以考虑在低峰时段进行全量刷新,并使用DB2的LOAD或INSERT方式优化刷新性能。
摘要表有一些使用限制需要提前评估。REFRESH IMMEDIATE模式虽然能自动同步,但不支持GROUP BY等聚合操作,因此大多数分析型摘要表只能选择DEFERRED。DEFERRED模式的数据延迟必须被业务端接受,否则查询结果可能不是最新的。另外,摘要表的数据不能直接通过INSERT、UPDATE或DELETE修改,它的内容只能由REFRESH TABLE命令重建。如果源表结构发生变化,例如删除了摘要表用到的列,摘要表也需要删除后重新创建。
维护方面,建议定期查看访问计划确认摘要表是否真正被优化器使用。如果建立后一直未被命中,说明查询模式与摘要表定义不匹配,或者CURRENT REFRESH AGE没有正确设置。对于那些长期不用的摘要表,应该及时清理,因为每多一张冗余表就会增加存储占用,也可能影响ETL维护成本。相反,对于命中率高、收益明显的摘要表,可以进一步扩展维度或创建多个聚合级别,例如日汇总、月汇总和区域汇总,形成分层汇总结构。
总体来说,DB2摘要表的本质是用存储空间换取查询时间。它适合读多写少、聚合查询频繁、数据延迟容忍度较高的数据仓库和BI场景。在OLTP系统中滥用摘要表,会因为刷新开销和存储冗余带来反效果。合理使用摘要表的关键在于:选对聚合粒度、设置正确的刷新模式、配置CURRENT REFRESH AGE,并通过执行计划持续验证优化效果。
DB2摘要表Summary Table物化查询表修改时间:2026-08-26 09:17:59