DB2在判断能否使用物化查询表(MQT)时,默认会把权限检查放在优化器之前:用户除了要有底层表的SELECT权限,还必须拥有MQT本身的SELECT权限。这个严苛条件导致很多原本可以走预聚合结果的查询被迫回退到明细表扫描。opt_enable_partial_security就是用来解开这个限制的注册变量,它允许优化器在确认用户对底层表有权限后,使用用户无权直接访问的MQT。

opt_enable_partial_security解决了什么权限矛盾
在DB2的默认安全模型里,物化查询表会被当作普通表对象进行权限校验。也就是说,如果用户要执行的SQL语句本身没有直接引用MQT,但优化器在查询重写阶段希望用MQT替换掉对多个明细表的聚合计算,就必须确认该用户对MQT有SELECT权限。这个条件在开发库和测试库中往往不是问题,但在生产环境里,DBA通常会把MQT单独放入一个受控模式,并限制业务账号直接读取MQT,只开放明细表权限。结果就是优化器明明发现了更高效的预聚合路径,却因为权限不足而放弃使用。
opt_enable_partial_security对应的注册变量全名是DB2_OPT_ENABLE_PARTIAL_SECURITY。当该变量设置为YES时,DB2优化器允许一种“部分安全性”判断:如果用户对被查询的底层表拥有必要的SELECT权限,那么即使该用户对候选MQT没有SELECT权限,优化器仍然可以把MQT纳入执行计划。这个设计的前提是MQT的数据完全来源于这些底层表,MQT本身并没有包含超出底层表范围的新数据,因此使用MQT不会让用户看到额外的业务数据。
从安全性边界来看,部分安全性并不意味着用户可以绕过权限直接查询MQT。业务用户依然不能对MQT执行SELECT * FROM mqts.sales_summary,除非被显式授权。这个变量只是让优化器在内部重写查询时,不再因为MQT权限不足就一律跳过。换句话说,数据访问权限仍然由底层表决定,MQT只作为优化器可以选用的内部加速结构。
启用opt_enable_partial_security并确认生效
该参数属于实例级注册变量,需要先设置再重启Db2实例。假设当前实例名为db2inst1,可以在实例用户下执行以下命令完成配置。设置之后,同一个实例下的所有数据库都会受到这个变量的影响。
db2set DB2_OPT_ENABLE_PARTIAL_SECURITY=YES db2set -all
执行db2set -all可以查看当前实例已经生效的注册变量列表。如果之前已经设置过该变量,直接覆盖为新值即可。需要注意的是,DB2注册变量的修改通常不会动态生效,必须停止并重新启动实例才能让新的设置被数据库管理器加载。
db2stop force db2start
实例重启完成后,可以通过db2set -all | grep -i partial来快速检查变量是否存在。这里使用grep过滤只是为了方便定位,不会影响变量的实际值。确认显示DB2_OPT_ENABLE_PARTIAL_SECURITY=YES后,优化器在后续查询编译时就会启用部分安全性判断。
如果希望恢复默认行为,只要将该变量设置为NO,并再次重启实例即可。由于该变量属于优化器行为开关,设置不当的影响主要集中在执行计划选择上,不会改变用户的显式访问权限,也不会直接开放MQT数据读取接口。
结合物化查询表完成一个最小验证
下面通过一个简单的销售明细场景来观察部分安全性如何影响查询计划。先创建一张明细表,并在另一个模式下创建汇总MQT。为了模拟真实权限隔离,明细表放在sales模式,MQT放在mqts模式。
CREATE TABLE sales.orders (
order_id INT NOT NULL,
region VARCHAR(20),
amount DECIMAL(15,2)
);
CREATE TABLE mqts.sales_summary AS
(SELECT region, SUM(amount) AS total_amount
FROM sales.orders
GROUP BY region)
DATA INITIALLY DEFERRED
REFRESH DEFERRED
ENABLE QUERY OPTIMIZATION;创建完成后,先刷新MQT,否则延迟刷新模式下MQT内容可能为空,优化器无法使用。随后创建一个业务用户,只授予明细表sales.orders的SELECT权限,不授予MQT权限。
REFRESH TABLE mqts.sales_summary; GRANT SELECT ON sales.orders TO USER user2;
使用业务用户user2执行以下聚合查询。在默认配置下,优化器会直接扫描sales.orders明细表并做GROUP BY聚合。启用DB2_OPT_ENABLE_PARTIAL_SECURITY=YES之后,优化器可以在无法直接访问MQT的情况下,把查询重写为读取mqts.sales_summary,从而减少明细行扫描和运行期聚合开销。
SELECT region, SUM(amount) AS total_amount FROM sales.orders GROUP BY region;
如果要确认执行计划是否真正使用了MQT,可以使用EXPLAIN工具生成计划文件。重点查看计划中是否出现mqts.sales_summary对象。对于用户无权限直接访问的MQT,计划中通常会显示为优化器内部选择的表访问节点,而不是普通表扫描。通过对比设置前后两个执行计划,可以直观看到部分安全性开关对MQT选择的影响。
常见问题与排查思路
启用该变量后,优化器仍然可能没有选择MQT。这时需要检查MQT本身是否满足优化器使用条件。例如MQT是否已经通过REFRESH TABLE刷新,当前查询的CURRENT REFRESH AGE是否允许读取延迟刷新数据,以及查询中的谓词是否与MQT定义完全匹配。任意一个条件不满足,都会导致MQT无法进入候选集合,这与权限开关无关。
还要注意部分安全性并不能突破底层表权限。如果业务用户对MQT定义中引用的某张底层表没有SELECT权限,即使其他底层表可以访问,优化器也不会使用该MQT。因为从安全角度看,MQT可能聚合了该用户本不应该看到的底层表数据。只有用户对MQT涉及的所有底层表都具备必要权限时,部分安全性机制才会放行优化器使用该MQT。
实际排障时,建议先关闭该变量执行一次查询,再开启该变量执行相同查询,并使用db2exfmt比对执行计划。这样能够清楚区分是权限阻塞还是优化器成本估算导致的选择差异。对于已经稳定的生产系统,修改优化器行为前应在测试环境进行充分回归,尤其是涉及复杂MQT、连接顺序和星型连接的场景。
DB2opt_enable_partial_security物化查询表修改时间:2026-09-20 07:15:48