Hi Hackers,

My company (NTT Comware) and NTT OSS Center did verification of
partitioned table on PG14dev, and we faced a problem that consumed
huge memory when we created a Foreign key constraint on a partitioned
table including 500 partitioning tables and inserted some data.

We investigated it a little to use the "pg_backend_memory_contextes"
command and realized a "CachedPlan" of backends increased dramatically.
See below:

Without FKs
==============================
CachedPlan 0kB

With FKs (the problem is here)
==============================
CachedPlan 710MB


Please find the attached file to reproduce the problem.

We know two things as following:
  - Each backend uses the size of CachedPlan
  - The more increasing partitioning tables, the more CachedPlan
    consuming

If there are many backends, it consumes about the size of CachedPlan x
the number of backends. It may occur a shortage of memory and OOM killer.
We think the affected version are PG12 or later. I believe it would be
better to fix the problem. Any thoughts?

Regards,
Tatsuro Yamada
DROP TABLE IF EXISTS pr CASCADE;
DROP TABLE IF EXISTS ps CASCADE;
CREATE TABLE ps (c1 INT PRIMARY KEY) PARTITION BY RANGE(c1);
CREATE TABLE pr (c1 INT, c2 INT REFERENCES ps(c1)) PARTITION BY RANGE(c1);

-- Show memory usage of 'Cached%' 
SELECT name, sum(used_bytes) as bytes, pg_size_pretty(sum(used_bytes)) FROM 
pg_backend_memory_contexts
WHERE name LIKE 'Cached%' GROUP BY name;

-- Procedure for creating partitioned table
CREATE OR REPLACE PROCEDURE part_make(tbl text, num int) AS $$
 DECLARE width int := 10; next int :=1;
 BEGIN
   FOR i in 1..num LOOP
       EXECUTE 'CREATE TABLE ' || tbl || '_' || i || ' partition of ' || tbl || 
' FOR VALUES FROM (' || next || ') TO (' || i * width
           || ');';
               next := i * width;
   END LOOP;
 END;
$$ LANGUAGE plpgsql;

-- Create partitioned tables named ps and pr. The each table has 500 
partitioning tables. 
CALL part_make('ps', 500);
CALL part_make('pr', 500);

-- Insert data
INSERT INTO ps SELECT generate_series(1,4999);
INSERT INTO pr SELECT i, i from generate_series(1,4999)i;

-- Show memory usages of 'Cached%' again
-- You can see 'CachedPlan 710MB'
SELECT name, sum(used_bytes) as bytes, pg_size_pretty(sum(used_bytes)) FROM 
pg_backend_memory_contexts
WHERE name LIKE 'Cached%' GROUP BY name;

Reply via email to