A materialized query table is a warehouse trick built into DB2 for z/OS: store the answer to a heavy GROUP BY once, then let the optimizer rewrite similar queries to read that stored answer. This page covers CREATE TABLE AS, REFRESH TABLE, deferred versus immediate refresh, ENABLE/DISABLE QUERY OPTIMIZATION, maintenance, statistics, dependencies, and the restrictions that surprise beginners coming from Db2 LUW.
A view stores only the SELECT text. An MQT stores the rows. When a user writes SUM(AMOUNT) GROUP BY YEAR against a billion-row fact table, Db2 can notice you already materialized that grain and read the small MQT instead. That process is automatic query rewrite (AQR). The user does not name the MQT.
You can also SELECT from the MQT by name, like any table. That is useful while you test refresh quality. Production reporting can use either path: explicit MQT names, or AQR against the base tables.
The fullselect plus DATA INITIALLY DEFERRED and REFRESH DEFERRED is what makes the table an MQT on z/OS. Column names can be listed before AS or taken from the select list.
1234567891011CREATE TABLE FIN.TRAN_BY_YEAR (YEAR, TXN_COUNT, AMOUNT_SUM) AS ( SELECT YEAR, COUNT(*), SUM(AMOUNT) FROM FIN.TRAN GROUP BY YEAR ) DATA INITIALLY DEFERRED REFRESH DEFERRED MAINTAINED BY SYSTEM DISABLE QUERY OPTIMIZATION;
| Clause | Meaning |
|---|---|
| AS (fullselect) | Defines the derived columns and source query |
| DATA INITIALLY DEFERRED | CREATE does not populate rows (z/OS required pattern) |
| REFRESH DEFERRED | Contents stay until REFRESH TABLE or user DML |
| MAINTAINED BY SYSTEM | USER | Who is allowed to change the MQT data |
| ENABLE | DISABLE QUERY OPTIMIZATION | Whether AQR may consider this MQT |
IBM’s sample uses ENABLE QUERY OPTIMIZATION on CREATE. Many shops still create DISABLE, refresh, collect statistics, then ALTER TABLE … ENABLE QUERY OPTIMIZATION so the optimizer never sees an empty MQT.
You can also ALTER an existing table into an MQT (or convert an MQT back to a base table). That is how you attach a fullselect to a table you already loaded.
REFRESH DEFERRED means “stale until I say otherwise.” On Db2 for z/OS this is the supported refresh mode. You run REFRESH TABLE FIN.TRAN_BY_YEAR in batch. Until then, AQR may still use the MQT if special registers allow deferred tables—knowing the numbers can be hours old.
REFRESH IMMEDIATE on Db2 LUW maintains the MQT in the same unit of work as base-table INSERT/UPDATE/DELETE. That option is not available on Db2 for z/OS the way LUW implements it. If you need near-real-time summaries on z/OS, use triggers or a user-maintained MQT you update yourself, or offload to the Analytics Accelerator—not REFRESH IMMEDIATE in z/OS DDL.
1REFRESH TABLE FIN.TRAN_BY_YEAR;
ENABLE QUERY OPTIMIZATION allows AQR. DISABLE QUERY OPTIMIZATION forbids AQR but still allows direct SQL against the MQT. The fullselect you write for ENABLE is more restricted (IBM documents which constructs AQR can match). A DISABLE MQT can use a more exotic SELECT because only humans will query it.
Special registers that gate AQR:
123456SET CURRENT REFRESH AGE ANY; SET CURRENT MAINTAINED TABLE TYPES FOR OPTIMIZATION = ALL; SELECT YEAR, SUM(AMOUNT) FROM FIN.TRAN GROUP BY YEAR;
MQT maintenance is either system (REFRESH TABLE only, plus utilities that IBM allows) or user (you LOAD/INSERT). System-maintained MQTs generally need at least one REFRESH TABLE before AQR will trust them. User-maintained MQTs do not get a Db2-maintained REFRESH_TIME the same way—you are responsible for freshness.
MQT refresh cost is a full recompute: scan sources, aggregate, replace MQT rows. Lock and log like a warehouse LOAD. Do it when sources are quiet, then RUNSTATS.
MQT dependencies: the fullselect references base tables, views, or functions. DROP or incompatible ALTER of a source can invalidate the MQT. Check catalog dependency tables before you drop a fact table that an MQT sits on.
MQT statistics are ordinary RUNSTATS on the MQT table space. Without them AQR cannot compare cost. After every refresh, RUNSTATS TABLESPACE … TABLE(the MQT) INDEX(ALL). Real-time statistics help too, but a full RUNSTATS after a complete replace is the safe habit.
Query rewrite matches SELECT lists, GROUP BY columns, and predicates. A query that groups by YEAR, MONTH will not use an MQT that only groups by YEAR unless Db2 can derive the answer (usually it cannot). Equality predicates on extra dimensions also block a match. EXPLAIN is how you prove AQR fired.
MQT performance wins when many queries share one grain and refresh is rare compared with reads. It loses when every refresh scans the same fact table you were trying to avoid, or when DASD for the MQT rivals the base table.
MQT restrictions (z/OS):
Imagine counting every gold star in the school every time a teacher asks “how many stars this year?” An MQT is a poster on the wall with the totals already written. REFRESH TABLE is the night janitor who recounts and reprints the poster. ENABLE QUERY OPTIMIZATION means teachers who ask the long question get sent to the poster automatically. DISABLE means they must walk up and read the poster by name. REFRESH IMMEDIATE would be reprinting the poster after every single new star—that printer exists on LUW, not on z/OS, so the janitor works on a schedule instead.
1. What is an MQT?
2. On Db2 for z/OS, REFRESH IMMEDIATE:
3. ENABLE QUERY OPTIMIZATION means:
4. REFRESH TABLE does what?
5. Which is a documented MQT restriction?