feat: add data lineage - #20198
Conversation
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
9997af8 to
a5def34
Compare
a5def34 to
f46b5bc
Compare
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
74e7d45 to
1136d19
Compare
1136d19 to
99239b6
Compare
drmingdrmer
left a comment
There was a problem hiding this comment.
@drmingdrmer reviewed 20 files and made 1 comment.
Reviewable status: 20 of 76 files reviewed, 1 unresolved discussion (waiting on youngsofun).
src/meta/app/src/schema/lineage.rs line 24 at r1 (raw file):
pub enum LineageDirection { Upstream, Downstream,
it's very unclear what direction is UPSTREAM and what is DOWNSTREAM. there is no common knowledge on it and there is no comment explaining it. choose better terms
Code quote:
pub enum LineageDirection {
Upstream,
Downstream,
drmingdrmer
left a comment
There was a problem hiding this comment.
it's too big a PR and I do not think I can review it thoroughly.
I'm gonna just approve it. And please let the LLM review it. And if LLM say yes, just merge it.
Good point. I propose separating the user-facing traversal direction from the physical Meta index layout.
For the Meta keys, I propose enum LineageIndex {
/// Stores the edge as `object = source` and `related_object = target`.
/// Prefix scans enumerate downstream targets of a source.
BySource,
/// Stores the edge as `object = target` and `related_object = source`.
/// Prefix scans enumerate upstream sources of a target.
ByTarget,
}Individual lineage edges and result columns will use This makes each context explicit:
|
I hereby agree to the terms of the CLA available at: https://docs.databend.com/dev/policies/cla/
Summary
This PR adds persistent object-level and column-level data lineage, lifecycle handling, and the Enterprise
GET_LINEAGEtable function.Related PRs
mainand drop that duplicate commit.ALTER VIEWquery and output-column changes. It was split out so the behavioral change can be reviewed independently. This PR no longer contains or depends on that change.The remaining changes stay together because the metadata schema, metadata API, persistence paths, lifecycle behavior,
GET_LINEAGE, and SQL workflow tests share the same identity and column-mapping contract. Intermediate subsets would not provide a complete or meaningfully testable user workflow.Reviewing commit by commit is recommended:
GET_LINEAGEtable function.This PR persists lineage for:
CREATE VIEWCREATE TABLE ... AS SELECT ...(CTAS)INSERT ... SELECTREPLACE INTO ... SELECTUPDATE ... FROMMERGECOPY INTOpersistence hooks are prepared, but extraction ofPlan::CopyIntoTablesources is not included yet.Motivation
Databend currently has no persistent metadata representation for tracing where tables and columns originate or where their data flows. This PR adds persistent bidirectional lineage metadata, column-level mappings, and a Snowflake-style
GET_LINEAGEtable function.Lineage model
A lineage edge always follows the canonical direction:
Objects with stable table IDs use ID-addressed lineage. Name-addressed lineage is used for name-bound dependencies, including view references and tables without stable lineage IDs.
Views form a lineage boundary: DML reading from a view records the view rather than expanding directly to its base tables. Streams behave differently: stream data columns are attributed to the base table, while stream metadata columns are ignored.
Self-referential writes do not create lineage loops. For example,
INSERT INTO t SELECT * FROM tdoes not create at -> tedge.Metadata and persistence
Each edge is stored in both directions under a tenant-scoped structured key. Structured key encoding provides escaping for object names and integrates with metactl, snapshots, backups, and tenant export/filter tooling.
Structural lineage is committed atomically with object metadata for
CREATE VIEWand CTAS. DML lineage is persisted after a successful table commit using a best-effort callback; lineage write failures do not change a successful DML result.DML merge operations preserve the existing lineage kind, update the last query metadata, and merge column edges without duplicates. Lineage metadata does not currently use TTL.
GET_LINEAGE
GET_LINEAGEis implemented as a table function:GET_LINEAGE( '<object_name>', '<object_domain>', '<direction>' [, distance] )Supported domains are
TABLE,VIEW,COLUMN, andSTAGE. Supported directions areUPSTREAMandDOWNSTREAM; distance defaults to 5 and must be between 1 and 5.The implementation uses a distance-ordered BFS. Metadata listing and object resolution are concurrent within each level, while levels remain sequential to preserve distance semantics. Query-time resolution validates the current object and column state.
GET_LINEAGEis gated by the EnterpriseFeature::Lineagelicense feature.Capture configuration
Capture is controlled independently from the Enterprise license:
The default is
false. This allows deployments that need lineage to opt into its planning and metadata costs. Capture remains stable across license changes, while querying throughGET_LINEAGErequires the Enterprise feature.Object lifecycle
Current limitations
COPY INTOsource lineage extraction is not implemented yet.GET_LINEAGEdomain because lineage passes through to its base table.AS MATERIALIZEDCTE lineage is not included yet.Tests
Coverage includes metadata key encoding, protobuf compatibility, lineage API behavior, BFS traversal, column propagation, CTAS, views, DML workflows, multi-table insert, rename/drop/undrop behavior, vacuum cleanup, cross-database ID resolution, self-writes, filter-only columns, aggregate expressions, CTEs, subqueries, and stream passthrough.
Type of change
This change is