Per-graph LIST partitions
Each
graph_idis its own Postgres LIST partition of_pgrdf_quads. Adding one is one UDF call; dropping a whole graph is a partition detach, not a row scan.
What it does
pgrdf.add_graph(graph_id BIGINT) → BOOLEANpgrdf.count_quads(graph_id BIGINT DEFAULT 0) → BIGINT
pgrdf._pgrdf_quads is LIST-partitioned on graph_id. Each call to pgrdf.add_graph(N) creates (or returns the existing) child partition for that id. pgrdf.count_quads(N) returns the row count of that partition.
Why you'd use it
- Project managers — multi-tenant and multi-ontology workloads get cheap isolated namespaces. Rolling back a load run is a partition detach, not a
DELETE. - Data scientists — version your knowledge graph by partition; query the live graph and a frozen snapshot in the same SQL session.
- Ontologists — keep each loaded vocabulary in its own partition for clean composition + lifecycle.
Example
-- Allocate three partitions.
SELECT pgrdf.add_graph(1); -- → true (new)
SELECT pgrdf.add_graph(2); -- → true
SELECT pgrdf.add_graph(1); -- → false (already exists)
-- Load some data into each.
SELECT pgrdf.parse_turtle('@prefix ex:<http://e.com/>. ex:a ex:p ex:b .', 1);
SELECT pgrdf.parse_turtle('@prefix ex:<http://e.com/>. ex:c ex:p ex:d .', 2);
-- Per-partition counts are cheap.
SELECT pgrdf.count_quads(1); -- → 1
SELECT pgrdf.count_quads(2); -- → 1For an explicit IRI ↔ id binding, see Named graphs.
How it works
_pgrdf_quads is declared PARTITION BY LIST (graph_id); each add_graph(N) call issues CREATE TABLE … PARTITION OF _pgrdf_quads FOR VALUES IN (N). The covering indexes (SPO/POS/OSP) are declared on the parent table and inherited.
✅ Graph lifecycle UDFs shipped — drop_graph, clear_graph, copy_graph, move_graph are now first-class partition-level primitives. See Graph lifecycle UDFs for the overview, or the individual pages: drop_graph, clear_graph, copy_graph, move_graph.