Table Function Scan
Appears in EXPLAIN asTable Function Scan
Reads rows from XMLTABLE / JSON_TABLE.
What it is
A Table Function Scan produces relational rows from a structured-document function such as XMLTABLE (and JSON_TABLE), turning XML/JSON into columns.
When the planner picks it
When the query uses XMLTABLE or JSON_TABLE in FROM.
Is it good or bad?
Expected for document shredding. Parsing large documents per row is the cost to watch.
In depth
XMLTABLE and JSON_TABLE
A Table Function Scan produces relational rows from a structured-document
function:
XMLTABLE(…)— turns an XML document into columns according to an XPath / row-pattern definition.JSON_TABLE(…)(PostgreSQL 17+) — does the same for JSON documents using SQL/JSON path expressions.
SELECT *
FROM JSON_TABLE(
(SELECT doc FROM orders WHERE id = 42),
'$.lines[*]' COLUMNS (
sku text PATH '$.sku',
qty int PATH '$.qty'
)
);
The node parses the source document, walks the row pattern, and emits one row per match. It's the cleanest way to shred semi-structured data into relational rows inline.
Where the cost goes
For one document the cost is parsing it once; for a query that calls
XMLTABLE / JSON_TABLE per row of a table, the cost is per-row parsing —
and you pay it again every time. If the documents are large, materializing
the shredded form once (into a regular table) is usually faster than calling
the table function repeatedly.
Stats are limited
Like ordinary Function Scan, the planner has limited information about how
many rows the table function will return. For hot paths over many documents,
declaring ROWS on a wrapping PL/pgSQL function — or pre-shredding into a
real table — gives the planner the figures it needs to choose well downstream.