Materialized views in Apache Drill provide a mechanism to store pre-computed query results for improved query performance. Unlike regular views which are virtual and execute the underlying query each time they are accessed, materialized views persist the query results as physical data that can be queried directly.
Materialized views are useful for:
Drill's materialized view implementation includes:
CREATE MATERIALIZED VIEW [schema.]view_name AS select_statement CREATE OR REPLACE MATERIALIZED VIEW [schema.]view_name AS select_statement CREATE MATERIALIZED VIEW IF NOT EXISTS [schema.]view_name AS select_statement
Examples:
-- Create a materialized view with aggregations CREATE MATERIALIZED VIEW dfs.tmp.sales_summary AS SELECT region, product_category, SUM(amount) as total_sales, COUNT(*) as num_transactions FROM dfs.`/data/sales` GROUP BY region, product_category; -- Create or replace an existing materialized view CREATE OR REPLACE MATERIALIZED VIEW dfs.tmp.customer_stats AS SELECT customer_id, COUNT(*) as order_count, AVG(order_total) as avg_order FROM dfs.`/data/orders` GROUP BY customer_id; -- Create only if it doesn't exist CREATE MATERIALIZED VIEW IF NOT EXISTS dfs.tmp.daily_metrics AS SELECT date_col, SUM(value) as daily_total FROM dfs.`/data/metrics` GROUP BY date_col;
DROP MATERIALIZED VIEW [schema.]view_name DROP MATERIALIZED VIEW IF EXISTS [schema.]view_name
Examples:
-- Drop a materialized view (error if not exists) DROP MATERIALIZED VIEW dfs.tmp.sales_summary; -- Drop only if it exists (no error if not exists) DROP MATERIALIZED VIEW IF EXISTS dfs.tmp.old_view;
REFRESH MATERIALIZED VIEW [schema.]view_name
The REFRESH command re-executes the underlying query and replaces the stored data with fresh results.
Example:
-- Refresh the materialized view with current data REFRESH MATERIALIZED VIEW dfs.tmp.sales_summary;
Drill supports automatic query rewriting where queries against base tables can be transparently rewritten to use materialized views when appropriate. This feature leverages Apache Calcite's SubstitutionVisitor for structural query matching.
Query rewriting is controlled by the planner.enable_materialized_view_rewrite option:
-- Enable materialized view rewriting (enabled by default) SET `planner.enable_materialized_view_rewrite` = true; -- Disable materialized view rewriting SET `planner.enable_materialized_view_rewrite` = false;
When query rewriting is enabled, Drill's query planner:
Query rewriting can apply in several scenarios:
Exact Match: The user's query exactly matches the MV definition.
-- MV definition CREATE MATERIALIZED VIEW dfs.tmp.region_totals AS SELECT r_regionkey, COUNT(*) as cnt FROM cp.`region.json` GROUP BY r_regionkey; -- This query will use the MV SELECT r_regionkey, COUNT(*) as cnt FROM cp.`region.json` GROUP BY r_regionkey;
Partial Match with Additional Filters: The user's query adds filters on top of the MV.
-- This query may use the MV and apply the filter SELECT r_regionkey, cnt FROM dfs.tmp.region_totals WHERE cnt > 10;
Aggregate Rollup: Higher-level aggregations computed from MV aggregates.
Use EXPLAIN to see if a materialized view is being used:
EXPLAIN PLAN FOR SELECT r_regionkey, COUNT(*) FROM cp.`region.json` GROUP BY r_regionkey;
If the MV is used, the plan will show a scan of the materialized view data location rather than the original table.
Materialized view definitions are stored as JSON files with the .materialized_view.drill extension in the workspace directory. This follows the same pattern as regular Drill views (.view.drill files).
The definition file contains:
Example definition file structure:
{ "name": "sales_summary", "sql": "SELECT region, SUM(amount) as total FROM sales GROUP BY region", "fields": [ {"name": "region", "type": "VARCHAR"}, {"name": "total", "type": "DOUBLE"} ], "workspaceSchemaPath": ["dfs", "tmp"], "dataStoragePath": "sales_summary", "lastRefreshTime": 1706900000000, "refreshStatus": "COMPLETE" }
Materialized view data is stored as Parquet files in a directory named {view_name}_mv_data within the workspace. Parquet format provides:
For a materialized view named sales_summary in dfs.tmp, the storage structure would be:
/tmp/
sales_summary.materialized_view.drill # Definition file
sales_summary_mv_data/ # Data directory
0_0_0.parquet # Data files
0_0_1.parquet
...
When Drill Metastore is enabled, materialized view metadata is automatically synchronized to the central metastore. This provides:
Set the metastore.enabled option to enable metastore integration:
SET `metastore.enabled` = true;
When enabled, the following operations automatically sync to the metastore:
The MaterializedViewMetadataUnit stored in the metastore contains:
| Field | Type | Description |
|---|---|---|
| storagePlugin | String | Storage plugin name (e.g., “dfs”) |
| workspace | String | Workspace name (e.g., “tmp”) |
| name | String | Materialized view name |
| owner | String | Owner username |
| sql | String | Defining SQL statement |
| workspaceSchemaPath | List | Schema path components |
| dataLocation | String | Path to data directory |
| refreshStatus | String | INCOMPLETE or COMPLETE |
| lastRefreshTime | Long | Timestamp of last refresh |
| lastModifiedTime | Long | Timestamp of last modification |
| Option | Default | Description |
|---|---|---|
planner.enable_materialized_view_rewrite | true | Enables automatic query rewriting to use materialized views |
metastore.enabled | false | Enables Drill Metastore for centralized metadata storage |
Materialized views are exposed in the INFORMATION_SCHEMA.MATERIALIZED_VIEWS table. This allows users to query metadata about all materialized views in the system.
-- List all materialized views SELECT * FROM INFORMATION_SCHEMA.MATERIALIZED_VIEWS; -- List materialized views in a specific schema SELECT TABLE_NAME, REFRESH_STATUS, LAST_REFRESH_TIME FROM INFORMATION_SCHEMA.MATERIALIZED_VIEWS WHERE TABLE_SCHEMA = 'dfs.tmp'; -- Find materialized views that need refresh SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.MATERIALIZED_VIEWS WHERE REFRESH_STATUS = 'INCOMPLETE' OR REFRESH_STATUS IS NULL;
| Column | Type | Description |
|---|---|---|
| TABLE_CATALOG | VARCHAR | Catalog name (always “DRILL”) |
| TABLE_SCHEMA | VARCHAR | Schema name (e.g., “dfs.tmp”) |
| TABLE_NAME | VARCHAR | Materialized view name |
| VIEW_DEFINITION | VARCHAR | SQL statement that defines the materialized view |
| REFRESH_STATUS | VARCHAR | Current status: “INCOMPLETE” or “COMPLETE” |
| LAST_REFRESH_TIME | TIMESTAMP | When the materialized view was last refreshed |
| DATA_LOCATION | VARCHAR | File system path to the stored data |
Materialized views also appear in INFORMATION_SCHEMA.TABLES with TABLE_TYPE = 'MATERIALIZED VIEW':
-- List all materialized views via TABLES SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'MATERIALIZED VIEW';
Current limitations of the materialized view implementation:
Full Refresh Only: Incremental refresh is not yet supported. Each refresh completely replaces the stored data.
No Automatic Refresh: Materialized views must be manually refreshed. There is no automatic refresh mechanism based on source data changes.
Single Workspace: Materialized views can only be created in file-system based workspaces that support write operations.
No Partitioning: Materialized view data is not partitioned. All data is stored in a single directory.
Query Rewriting Scope: Query rewriting works best for exact or near-exact matches. Complex transformations may not be recognized.
| Class | Package | Description |
|---|---|---|
| MaterializedView | org.apache.drill.exec.dotdrill | Data model for MV definition |
| DrillMaterializedViewTable | org.apache.drill.exec.planner.logical | TranslatableTable implementation |
| MaterializedViewHandler | org.apache.drill.exec.planner.sql.handlers | SQL handler for CREATE/DROP/REFRESH |
| MaterializedViewRewriter | org.apache.drill.exec.planner.logical | Query rewriting using Calcite |
| SqlCreateMaterializedView | org.apache.drill.exec.planner.sql.parser | SQL parser for CREATE |
| SqlDropMaterializedView | org.apache.drill.exec.planner.sql.parser | SQL parser for DROP |
| SqlRefreshMaterializedView | org.apache.drill.exec.planner.sql.parser | SQL parser for REFRESH |
The SQL parser grammar for materialized views is defined in parserImpls.ftl. The grammar supports:
The MaterializedViewRewriter class implements query rewriting:
The SubstitutionVisitor performs structural matching by:
TestMaterializedViewSqlParser: Parser syntax validationTestMaterializedView: Data model serialization testsTestMaterializedViewSupport: End-to-end CREATE/DROP/REFRESH testsTestMaterializedViewRewriting: Query rewriting scenariosRun the tests with:
mvn test -pl exec/java-exec -Dtest='TestMaterializedView*'
Planned improvements for future releases:
Incremental Refresh: Support for refreshing only changed data based on source table modifications.
Automatic Refresh: Scheduled or trigger-based automatic refresh mechanisms.
Partitioned Storage: Partition materialized view data for better query performance.
Cost-Based Selection: When multiple MVs match, select based on estimated query cost.
Staleness Tracking: Track source table changes to identify stale materialized views.