Re: Partitioning versus autovacuum

From: Greg Stark <stark(at)mit(dot)edu>
To: Amit Langote <amitlangote09(at)gmail(dot)com>
Cc: PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Subject: Re: Partitioning versus autovacuum
Date: 2019-10-18 09:21:52
Message-ID: CAM-w4HO9hUHvJDVwQ8=Fgm-znF9WNvQiWsfyBjCr-5FD7gWKGA@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

At the risk of forking this thread... I think there's actually a
planner estimation bug here too.

Consider this test case of a simple partitioned table and a simple
join. The cardinality estimates for each partition and the Append node
are all perfectly accurate. But the estimate for the join is way off.
The corresponding test case without partitioning produces a perfect
cardinality estimate for the join.

I've never completely wrapped my head around the planner selectivity
estimations. IIRC join restrictions are treated differently from
single-relation restrictions. Perhaps what's happening here is that
the single-relation restrictions are being correctly estimated based
on the child partitions but the join restriction code hasn't been
taught the same tricks?

stark=# create table p (i integer, j integer) partition by list (i);
CREATE TABLE

stark=# create table p0 partition of p for values in (0);
CREATE TABLE
stark=# create table p1 partition of p for values in (1);
CREATE TABLE

stark=# insert into p select 0,generate_series(1,1000);
INSERT 0 1000
stark=# insert into p select 1,generate_series(1,1000);
INSERT 0 1000

stark=# analyze p0;
ANALYZE
stark=# analyze p1;
ANALYZE

stark=# create table q (i integer);
CREATE TABLE
stark=# insert into q values (0);
INSERT 0 1
stark=# analyze q;
ANALYZE

-- Query partitioned table, get wildly off row estimates for join

stark=# explain analyze select * from q join p using (i) where j
between 1 and 500;
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ QUERY PLAN

├─────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Hash Join (cost=1.02..44.82 rows=5 width=8) (actual
time=0.060..1.614 rows=500 loops=1) │
│ Hash Cond: (p0.i = q.i)

│ -> Append (cost=0.00..40.00 rows=1000 width=8) (actual
time=0.030..1.127 rows=1000 loops=1) │
│ -> Seq Scan on p0 (cost=0.00..20.00 rows=500 width=8)
(actual time=0.029..0.440 rows=500 loops=1) │
│ Filter: ((j >= 1) AND (j <= 500))

│ Rows Removed by Filter: 500

│ -> Seq Scan on p1 (cost=0.00..20.00 rows=500 width=8)
(actual time=0.018..0.461 rows=500 loops=1) │
│ Filter: ((j >= 1) AND (j <= 500))

│ Rows Removed by Filter: 500

│ -> Hash (cost=1.01..1.01 rows=1 width=4) (actual
time=0.011..0.012 rows=1 loops=1) │
│ Buckets: 1024 Batches: 1 Memory Usage: 9kB

│ -> Seq Scan on q (cost=0.00..1.01 rows=1 width=4) (actual
time=0.005..0.006 rows=1 loops=1) │
│ Planning time: 0.713 ms

│ Execution time: 1.743 ms

└─────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
(14 rows)

-- Query non-partitioned table get accurate row estimates for join

stark=# create table pp as (Select * from p);
SELECT 2000
stark=# analyze pp;
ANALYZE

stark=# explain analyze select * from q join pp using (i) where j
between 1 and 500;
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ QUERY PLAN

├─────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Hash Join (cost=1.02..48.77 rows=500 width=8) (actual
time=0.027..0.412 rows=500 loops=1) │
│ Hash Cond: (pp.i = q.i)

│ -> Seq Scan on pp (cost=0.00..39.00 rows=1000 width=8) (actual
time=0.014..0.243 rows=1000 loops=1) │
│ Filter: ((j >= 1) AND (j <= 500))

│ Rows Removed by Filter: 1000

│ -> Hash (cost=1.01..1.01 rows=1 width=4) (actual
time=0.005..0.005 rows=1 loops=1) │
│ Buckets: 1024 Batches: 1 Memory Usage: 9kB

│ -> Seq Scan on q (cost=0.00..1.01 rows=1 width=4) (actual
time=0.003..0.003 rows=1 loops=1) │
│ Planning time: 0.160 ms

│ Execution time: 0.456 ms

└─────────────────────────────────────────────────────────────────────────────────────────────────────────┘
(10 rows)

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Alvaro Herrera 2019-10-18 09:56:36 Re: Obsolete comment in partbounds.c
Previous Message Michael Banck 2019-10-18 09:05:52 Re: [Patch] Base backups and random or zero pageheaders