Hi there, my question is, shouldn't
a query that spans all partitions in a partionend table be roughly the same in performance as one on
a non partionend table? I'm getting roughly 50% slower performance on a partioned table.
I have tried this on a macbook and ubuntu server. More details are below.
The queries:
EXPLAIN (ANALYZE, VERBOSE, BUFFERS, COSTS) SELECT COUNT(*) FROM logs WHERE event = 'rewinded';
EXPLAIN (ANALYZE, VERBOSE, BUFFERS, COSTS) SELECT COUNT(*) FROM logs_partioned WHERE event = 'rewinded';
----
The results:
EXPLAIN (ANALYZE, VERBOSE, BUFFERS, COSTS) SELECT COUNT(*) FROM logs WHERE event = 'rewinded';
QUERY PLAN
Finalize Aggregate (cost=93673.28..93673.29 rows=1 width=8) (actual time=163.160..164.321 rows=1 loops=1)
Output: count(*)
Buffers: shared hit=6929
-> Gather (cost=93672.86..93673.27 rows=4 width=8) (actual time=163.088..164.314 rows=4 loops=1)
Output: (PARTIAL count(*))
Workers Planned: 4
Workers Launched: 3
Buffers: shared hit=6929
-> Partial Aggregate (cost=92672.86..92672.87 rows=1 width=8) (actual time=154.476..154.477 rows=1 loops=4)
Output: PARTIAL count(*)
Buffers: shared hit=6929
Worker 0: actual time=150.627..150.628 rows=1 loops=1
Buffers: shared hit=1725
Worker 1: actual time=152.368..152.368 rows=1 loops=1
Buffers: shared hit=1718
Worker 2: actual time=152.219..152.220 rows=1 loops=1
Buffers: shared hit=1727
-> Parallel Index Only Scan using logs_event_idx on public.logs (cost=0.57..87681.79 rows=1996428 width=0) (actual time=0.101..90.809 rows=1976526 loops=4)
Output: event
Index Cond: (logs.event = 'rewinded'::text)
Heap Fetches: 854
Buffers: shared hit=6929
Worker 0: actual time=0.155..88.693 rows=1959750 loops=1
Buffers: shared hit=1725
Worker 1: actual time=0.106..89.503 rows=1969110 loops=1
Buffers: shared hit=1718
Worker 2: actual time=0.102..89.430 rows=1973790 loops=1
Buffers: shared hit=1727
Planning Time: 0.242 ms
Execution Time: 164.383 ms
(30 rows)
Time: 165.105 ms
-------
EXPLAIN (ANALYZE, VERBOSE, BUFFERS, COSTS) SELECT COUNT(*) FROM logs_partioned WHERE event = 'rewinded';
QUERY PLAN
Finalize Aggregate (cost=110643.80..110643.81 rows=1 width=8) (actual time=249.562..250.597 rows=1 loops=1)
Output: count(*)
Buffers: shared hit=6889
-> Gather (cost=110643.48..110643.79 rows=3 width=8) (actual time=249.522..250.593 rows=4 loops=1)
Output: (PARTIAL count(*))
Workers Planned: 3
Workers Launched: 3
Buffers: shared hit=6889
-> Partial Aggregate (cost=109643.48..109643.49 rows=1 width=8) (actual time=240.213..240.214 rows=1 loops=4)
Output: PARTIAL count(*)
Buffers: shared hit=6889
Worker 0: actual time=237.259..237.260 rows=1 loops=1
Worker 0: actual time=237.259..237.260 rows=1 loops=1
Buffers: shared hit=1678
Worker 1: actual time=237.244..237.245 rows=1 loops=1
Buffers: shared hit=1768
Worker 2: actual time=237.304..237.305 rows=1 loops=1
Buffers: shared hit=1699
-> Parallel Append (cost=0.44..103381.36 rows=2504849 width=0) (actual time=0.132..183.045 rows=1976526 loops=4)
Buffers: shared hit=6889
Worker 0: actual time=0.171..179.435 rows=1951389 loops=1
Buffers: shared hit=1678
Worker 1: actual time=0.160..181.963 rows=1954680 loops=1
Buffers: shared hit=1768
Worker 2: actual time=0.159..181.714 rows=1976309 loops=1
Buffers: shared hit=1699
-> Parallel Index Only Scan using logs_partioned_p2_event_idx on public.logs_partioned_p2 logs_partioned_2 (cost=0.44..23064.91 rows=638123 width=0) (actual time=0.129..47.947 rows=981544 loops=2)
Index Cond: (logs_partioned_2.event = 'rewinded'::text)
Heap Fetches: 0
Buffers: shared hit=1690
Worker 0: actual time=0.171..95.322 rows=1951389 loops=1
Buffers: shared hit=1678
Worker 1: actual time=0.087..0.571 rows=11700 loops=1
Buffers: shared hit=12
-> Parallel Index Only Scan using logs_partioned_p4_event_idx on public.logs_partioned_p4 logs_partioned_4 (cost=0.44..22982.75 rows=635850 width=0) (actual time=0.054..31.451 rows=663060 loops=3)
Index Cond: (logs_partioned_4.event = 'rewinded'::text)
Heap Fetches: 0
Buffers: shared hit=1712
Worker 1: actual time=0.001..0.001 rows=0 loops=1
Buffers: shared hit=1
Worker 2: actual time=0.158..93.844 rows=1976309 loops=1
Buffers: shared hit=1699
-> Parallel Index Only Scan using logs_partioned_p3_event_idx on public.logs_partioned_p3 logs_partioned_3 (cost=0.44..22398.42 rows=610946 width=0) (actual time=0.082..49.059 rows=993703 loops=2)
Index Cond: (logs_partioned_3.event = 'rewinded'::text)
Heap Fetches: 876
Buffers: shared hit=1794
Worker 1: actual time=0.159..96.371 rows=1942980 loops=1
Buffers: shared hit=1755
-> Parallel Index Only Scan using logs_partioned_p1_event_idx on public.logs_partioned_p1 logs_partioned_1 (cost=0.44..22397.29 rows=619632 width=0) (actual time=0.025..95.237 rows=1965505 loops=1)
Index Cond: (logs_partioned_1.event = 'rewinded'::text)
Heap Fetches: 0
Buffers: shared hit=1689
-> Parallel Index Only Scan using logs_partioned_default_event_idx on public.logs_partioned_default logs_partioned_5 (cost=0.29..13.74 rows=543 width=0) (actual time=0.035..0.269 rows=923 loops=1)
Index Cond: (logs_partioned_5.event = 'rewinded'::text)
Heap Fetches: 0
Buffers: shared hit=4
Planning Time: 0.496 ms
Execution Time: 250.672 ms
Time: 251.689 ms
----
The specs and test setup:
PostgreSQL 13.2 on arm-apple-darwin20.3.0, compiled by Apple clang version 12.0.0 (clang-1200.0.32.29), 64-bit
Macbook Air M1 8GB RAM 8 core
Settings:
name | current_setting | source
----------------------------------+--------------------+----------------------
application_name | psql | client
checkpoint_completion_target | 0.9 | configuration file
checkpoint_timeout | 30min | configuration file
client_encoding | UTF8 | client
DateStyle | ISO, MDY | configuration file
default_text_search_config | pg_catalog.english | configuration file
dynamic_shared_memory_type | posix | configuration file
effective_cache_size | 4GB | configuration file
lc_messages | C | configuration file
lc_monetary | C | configuration file
lc_numeric | C | configuration file
lc_time | C | configuration file
log_directory | log | configuration file
log_timezone | America/Anchorage | configuration file
logging_collector | on | configuration file
maintenance_work_mem | 1GB | configuration file
max_connections | 8 | configuration file
max_parallel_maintenance_workers | 2 | configuration file
max_parallel_workers | 4 | configuration file
max_parallel_workers_per_gather | 4 | configuration file
max_stack_depth | 2MB | environment variable
max_wal_size | 20GB | configuration file
max_worker_processes | 4 | configuration file
min_wal_size | 80MB | configuration file
random_page_cost | 1.1 | configuration file
shared_buffers | 2GB | configuration file
TimeZone | America/Anchorage | configuration file
vacuum_cost_limit | 2000 | configuration file
wal_buffers | 64MB | configuration file
wal_compression | on | configuration file
work_mem | 256MB | configuration file
--------------------
-- Queries:
CREATE OR REPLACE FUNCTION random_event() RETURNS TEXT AS
$$
DECLARE
id int;
events text[] := '{started,stopped,paused,closed,entered,rewinded,looped,skipped,ignored,playing,clicked,hovered,seeked,ignored,fastforwarded,repeated}';
BEGIN
return events[1 + (random() * array_length(events, 1))];
END
$$ LANGUAGE plpgsql;
CREATE TABLE logs(created TIMESTAMPTZ DEFAULT now(), event TEXT);
INSERT INTO logs SELECT generate_series, random_event() FROM generate_series('2020-01-01', '2021-01-01', interval '250 milliseconds');
VACUUM ANALYZE logs;
CREATE INDEX ON logs(event);
CREATE TABLE logs_partioned(created TIMESTAMPTZ DEFAULT now(), event TEXT) PARTITION BY RANGE(created);
CREATE TABLE logs_partioned_p1 PARTITION OF logs_partioned FOR VALUES FROM ('2020-01-01') TO ('2020-04-01');
CREATE TABLE logs_partioned_p2 PARTITION OF logs_partioned FOR VALUES FROM ('2020-04-01') TO ('2020-07-01');
CREATE TABLE logs_partioned_p3 PARTITION OF logs_partioned FOR VALUES FROM ('2020-07-01') TO ('2020-10-01');
CREATE TABLE logs_partioned_p4 PARTITION OF logs_partioned FOR VALUES FROM ('2020-10-01') TO ('2021-01-01');
CREATE TABLE logs_partioned_default PARTITION OF logs_partioned DEFAULT;
INSERT INTO logs_partioned SELECT * FROM logs;
VACUUM ANALYZE logs_partioned;
CREATE INDEX ON logs_partioned(event);