List PostgreSQL Partitioned Tables with SQL
How to List PostgreSQL Partitioned Tables
PostgreSQL table partitioning splits a large table into smaller physical pieces called child partitions. This improves query performance and simplifies data lifecycle management. But as a DBA, you need a quick way to see which tables in your database use partitioning — and which do not.
This SQL query reads directly from the PostgreSQL system catalogs to list every table in your database, labeling each as a partitioned table or an ordinary table, while excluding system schemas and child partition tables.
SQL Script
1SELECT
2 n.nspname AS "Schema",
3 c.relname AS "Name",
4 CASE c.relkind
5 WHEN 'p' THEN
6 'partitioned table'
7 WHEN 'r' THEN
8 'ordinary table'
9 ELSE
10 'unknown table type'
11 END AS "Type",
12 pg_catalog.pg_get_userbyid(c.relowner) AS "Owner"
13FROM
14 pg_catalog.pg_class c
15 JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
16WHERE
17 c.relkind = ANY ('{p,r,""}')
18 AND NOT c.relispartition
19 AND n.nspname !~ ALL ('{^pg_,^information_schema$}')
20ORDER BY
21 1,
22 2;
Notes: Works on PostgreSQL 10 and later, when declarative partitioning was introduced. Returns one row per table. Child partitions are excluded — only parent partitioned tables appear in the results.
Code Breakdown
pg_catalog.pg_class
The system catalog table that holds one row for every relation (table, index, sequence, view, etc.) in the database.
pg_catalog.pg_namespace
Holds schema names. Joined to pg_class on c.relnamespace = n.oid to get the human-readable schema name.
c.relkind
A single character that identifies the relation type. p means partitioned table, r means ordinary (regular) table.
CASE c.relkind
Translates the single-character code into a readable label. Only p and r are handled here; anything else returns unknown table type.
pg_catalog.pg_get_userbyid(c.relowner)
Converts the owner's OID (a numeric ID) into the role name that owns the table.
c.relkind = ANY ('{p,r,""}')
Filters to only partitioned tables and ordinary tables, skipping indexes, sequences, views, and other relation types.
NOT c.relispartition
Excludes child partition tables. Without this filter, every partition of every partitioned table would appear in the results. Only the parent table is shown.
n.nspname !~ ALL ('{^pg_,^information_schema$}')
Excludes system schemas. pg_ covers all internal PostgreSQL schemas. information_schema is the SQL-standard metadata schema.
ORDER BY 1, 2
Sorts results by schema name first, then table name, for easy reading.
Key Points
- Partitioned tables show as
partitioned table; all other user tables show asordinary table. - Child partitions (the actual physical storage pieces) are hidden by the
NOT c.relispartitionfilter. - The query covers all user schemas. To restrict to one schema, add
AND n.nspname = 'your_schema'. - The
Ownercolumn shows which role owns each table, which is useful when auditing permissions.
Insights and Explanations
PostgreSQL declarative partitioning (introduced in version 10) lets you split a table by a partition key — commonly a date range, a list of values, or a hash. Each child partition holds a subset of the rows. PostgreSQL routes queries to only the relevant partitions, which can dramatically cut query time on large tables.
This query helps you answer two questions quickly:
- Which tables in my database are partitioned?
- Which tables are plain ordinary tables that might benefit from partitioning if they grow large?
If a table appears as partitioned table, it is a parent table with child partitions beneath it. You can query pg_inherits to see those children:
1SELECT
2 parent.relname AS parent_table,
3 child.relname AS partition_name
4FROM
5 pg_inherits
6 JOIN pg_class parent ON pg_inherits.inhparent = parent.oid
7 JOIN pg_class child ON pg_inherits.inhrelid = child.oid
8WHERE
9 parent.relname = 'your_table_name';
If you see a table you expected to be partitioned showing as ordinary table, it may not have had partitioning applied yet, or the migration is still pending.
Additional Considerations
- PostgreSQL version: Declarative partitioning exists from PostgreSQL 10. On PostgreSQL 9.x and earlier, partitioning was done via table inheritance and trigger-based routing — this query will not identify those older-style partitioned tables correctly.
- Permissions: Any user can read
pg_classandpg_namespace. No superuser access is required. - Performance: This query reads only system catalog tables, which are small. It is safe to run at any time with no impact on production workloads.
- Child partition count: This query does not show how many partitions each parent has. Use
pg_inheritsfor that, or join to it here if needed.
References
Posts in this series
- How Many Connections Can Your PostgreSQL Database Handle?
- PostgreSQL Backend Connections via pg_stat_database
- Identifying Blocking PostgreSQL Queries using pg_stat_activity
- List PostgreSQL Databases by Size with Access Check
- Assess PostgreSQL Database Sizes Quickly and Easily
- Unveiling Your PostgreSQL Server - A Diagnostic Powerhouse
- Keep Your PostgreSQL Database Clean, Identify Idle Connections
- Query the PostgreSQL Configuration
- PostgreSQL Recovery Monitoring: Essential SQL Insights
- Restart All PostgreSQL Sequences with ALTER SEQUENCE
- Monitor Running Queries in PostgreSQL using pg_stat_activity
- Monitor PostgreSQL Active Sessions with pg_stat_activity
- PostgreSQL Error Handling Settings via pg_settings
- PostgreSQL File Location Settings Query via pg_settings
- PostgreSQL Lock Management Settings via pg_settings
- PostgreSQL Logging Configuration Query via pg_settings
- Monitor PostgreSQL Memory Settings with pg_settings
- PostgreSQL Table Row Count Estimates with SQL
- List PostgreSQL Tables by Size with SQL
- PostgreSQL WAL Settings Query Guide
- PostgreSQL SSL Settings Query Guide
- PostgreSQL Statistics Settings Query Guide
- PostgreSQL Resource Settings Query Guide
- PostgreSQL Replication Settings Query Guide
- PostgreSQL Query Planning Settings Query Guide
- PostgreSQL Preset Options Settings Query Guide
- PostgreSQL Miscellaneous Settings Query Guide
- Count PostgreSQL Sessions by State with SQL
- Kill Idle PostgreSQL Sessions with SQL
- Grant SELECT on All Tables in PostgreSQL
- Identify Insert-Only Tables in PostgreSQL
- Detect Soft Delete Patterns in PostgreSQL
- List PostgreSQL Object Comments with SQL
- List Foreign Key Constraints in PostgreSQL
- List PostgreSQL Enum Types and Their Values with SQL
- List All Views in a PostgreSQL Database with SQL
- Find PostgreSQL Tables Without a Primary Key
- List PostgreSQL Partitioned Tables with SQL