---
title: "Refresh a materialized view"
sidebarTitle: "Materialized View Refresh"
description: "A lakehouse object: a table defined by a query over another table, recomputed by each refresh."
icon: table
keywords: ["materialized view", "create_materialized_view", "refresh", "full refresh"]
---
import {
PyMaterializedViewCreate as MaterializedViewCreate,
PyMaterializedViewRefresh as MaterializedViewRefresh,
} from '/snippets/materialized_view.mdx';
A materialized view is a lakehouse object: a table whose contents are defined by
a query over another table. The query is recorded in the view's schema;
creating the view computes its rows, and a refresh computes them again.
The result is an ordinary table. It can be queried, indexed, and searched, and
it appears in `table_names()` — nothing about reading it is special.
In SQL this is [`REFRESH MATERIALIZED VIEW`](/sql/refresh#refresh-materialized-view).
## Create and refresh {#create-and-refresh}
{MaterializedViewCreate}
Creating the view computes its rows, so it is ready to read. Pass
`with_no_data=True` to create it empty instead. Later changes to the source
reach the view through a refresh:
{MaterializedViewRefresh}
These results were verified with the development SDK 0.40.0b13, built from
lancedb main. The published 0.39.0 differs: the source must be created with
stable row ids (the `new_table_enable_stable_row_ids` storage option),
`create_materialized_view` creates the view empty and has no `with_no_data`,
and `refresh()` still accepts `full`. Its first `refresh()` writes every
matching row, two in this example.
`select` takes column names, `(alias, expression)` pairs, or a dict of the same.
Omitting it selects every source column, expanded against the schema as it was
at creation time. `where` filters source rows; `limit` caps the view.
## Any table can be the source {#stable-row-ids}
The source needs no special storage option. A refresh does not track which
source rows the view came from, so stable row ids
(`new_table_enable_stable_row_ids`) are not required: the example above creates
its source with the defaults. Earlier development builds, and the published
0.39.0, required them.
## Every refresh rebuilds the view {#incremental}
`refresh()` runs the view's query against the source and replaces everything
the view holds with the result, in one commit. It does not reconcile changes:
`rows_written` is the size of the whole result — two after adding Bea, not
one — and a refresh with nothing new to read still rewrites the view and
commits a new table version.
`source_version=N` refreshes against that source version instead of the latest,
which is how a view reproduces a known point in time. There is no `full`
argument; every refresh is a full one.
## Against a deployment {#availability}
Enterprise
`create_materialized_view` and `refresh` also work on a `db://` connection.
There the SDK sends them to the deployment as SQL -- `CREATE MATERIALIZED VIEW`
and `REFRESH MATERIALIZED VIEW` -- and the work runs on the cluster rather than
in your process. `source_version` is for local views only; the SDK refuses it
on a remote refresh.
Materialized views are experimental on a deployment, which has to have them
enabled. How its refresh works -- rebuilding the whole view, as above, or
reconciling what changed in the source -- depends on its LanceDB Enterprise
version and configuration, and so do the options
[`REFRESH MATERIALIZED VIEW`](/sql/dml/refresh#refresh-materialized-view)
accepts.
`SHOW MATERIALIZED VIEWS` lists them, which is cheaper than
`list_materialized_views` -- that method finds views by reading every table's
schema, so it costs one open per table.
## Working with the view {#working-with-the-view}
`view.table` is the underlying table, for querying, indexing, or search.
`view.definition` is the recorded query — the select list, predicate, and
limit — which is how you check what a view actually contains without inferring
it from the rows. Both are properties; on an async view, the definition is read
with `await view.definition()`.
An existing view is reopened with `db.open_materialized_view(name)`.
## What to read next {#next}
Derive a column instead of a whole table.
Every refresh commits a table version.