Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- On PG 9.1 and 9.2 I'm running the following query:
- SELECT
- *
- FROM
- stream_store
- JOIN
- (
- SELECT
- UNNEST(stream_store_ids) AS id
- FROM
- stream_store_version_index
- WHERE
- stream_id = 607106 AND
- version = 11
- ) AS records USING (id)
- ORDER BY
- id DESC
- This takes several (10 to 20) milliseconds at most.
- When I add a LIMIT 1 to the end of the query, the query time goes to several hours(!).
- The full version String of PG 9.1 is "PostgreSQL 9.1.5 on x86_64-unknown-linux-gnu, compiled by gcc-4.4.real (Debian 4.4.5-8) 4.4.5, 64-bit". The 9.1 machine is a socket 771 dual quad core at 3.16Ghz with 64GB memory and 10 Intel x25M SSDs in a RAID5 setup on 2 ARECA 1680 RAID controllers. The "stream_store" table has 122 million rows and is partitioned. The array that's being unnested for the join has 27 entries.
- Without the LIMIT 1, the plan is as follows:
- "Sort (cost=247270.56..248786.41 rows=606341 width=1191) (actual time=0.476..0.479 rows=27 loops=1)"
- " Sort Key: public.stream_store.id"
- " Sort Method: quicksort Memory: 38kB"
- " -> Nested Loop (cost=0.00..23.80 rows=606341 width=1191) (actual time=0.070..0.409 rows=27 loops=1)"
- " Join Filter: (public.stream_store.id = (unnest(stream_store_version_index.stream_store_ids)))"
- " -> Index Scan using stream_store_version_index_unique_idx on stream_store_version_index (cost=0.00..2.67 rows=1 width=383) (actual time=0.027..0.035 rows=27 loops=1)"
- " Index Cond: ((stream_id = 607106) AND (version = 11))"
- " -> Append (cost=0.00..21.03 rows=7 width=1296) (actual time=0.008..0.012 rows=1 loops=27)"
- " -> Seq Scan on stream_store (cost=0.00..0.00 rows=1 width=1385) (actual time=0.000..0.000 rows=0 loops=27)"
- " -> Index Scan using stream_store_slice0_id on stream_store_slice0 stream_store (cost=0.00..2.67 rows=1 width=1385) (actual time=0.001..0.001 rows=0 loops=27)"
- " Index Cond: (id = (unnest(stream_store_version_index.stream_store_ids)))"
- " -> Index Scan using stream_store_slice1_id on stream_store_slice1 stream_store (cost=0.00..2.67 rows=1 width=1385) (actual time=0.000..0.000 rows=0 loops=27)"
- " Index Cond: (id = (unnest(stream_store_version_index.stream_store_ids)))"
- " -> Index Scan using stream_store_slice2_id on stream_store_slice2 stream_store (cost=0.00..4.93 rows=1 width=1179) (actual time=0.002..0.002 rows=0 loops=27)"
- " Index Cond: (id = (unnest(stream_store_version_index.stream_store_ids)))"
- " -> Index Scan using stream_store_slice3_id on stream_store_slice3 stream_store (cost=0.00..3.95 rows=1 width=1244) (actual time=0.003..0.004 rows=1 loops=27)"
- " Index Cond: (id = (unnest(stream_store_version_index.stream_store_ids)))"
- " -> Index Scan using stream_store_slice4_id on stream_store_slice4 stream_store (cost=0.00..4.15 rows=1 width=1110) (actual time=0.003..0.003 rows=0 loops=27)"
- " Index Cond: (id = (unnest(stream_store_version_index.stream_store_ids)))"
- " -> Index Scan using stream_store_slice5_id on stream_store_slice5 stream_store (cost=0.00..2.67 rows=1 width=1385) (actual time=0.000..0.000 rows=0 loops=27)"
- " Index Cond: (id = (unnest(stream_store_version_index.stream_store_ids)))"
- With the LIMIT the plan is (explained without analyze):
- "Limit (cost=0.11..108.42 rows=1 width=1191)"
- " -> Nested Loop (cost=0.11..65673570.30 rows=606341 width=1191)"
- " Join Filter: (public.stream_store.id = (unnest(stream_store_version_index.stream_store_ids)))"
- " -> Merge Append (cost=0.11..63854546.10 rows=121268101 width=1192)"
- " Sort Key: public.stream_store.id"
- " -> Sort (cost=0.01..0.02 rows=1 width=1385)"
- " Sort Key: public.stream_store.id"
- " -> Seq Scan on stream_store (cost=0.00..0.00 rows=1 width=1385)"
- " -> Index Scan Backward using stream_store_slice0_id on stream_store_slice0 stream_store (cost=0.00..45.40 rows=50 width=1385)"
- " -> Index Scan Backward using stream_store_slice1_id on stream_store_slice1 stream_store (cost=0.00..45.40 rows=50 width=1385)"
- " -> Index Scan Backward using stream_store_slice2_id on stream_store_slice2 stream_store (cost=0.00..34256230.75 rows=68710693 width=1179)"
- " -> Index Scan Backward using stream_store_slice3_id on stream_store_slice3 stream_store (cost=0.00..21294584.57 rows=39126729 width=1244)"
- " -> Index Scan Backward using stream_store_slice4_id on stream_store_slice4 stream_store (cost=0.00..4595998.21 rows=13430528 width=1110)"
- " -> Index Scan Backward using stream_store_slice5_id on stream_store_slice5 stream_store (cost=0.00..45.40 rows=50 width=1385)"
- " -> Materialize (cost=0.00..2.69 rows=1 width=8)"
- " -> Index Scan using stream_store_version_index_unique_idx on stream_store_version_index (cost=0.00..2.67 rows=1 width=383)"
- " Index Cond: ((stream_id = 607106) AND (version = 11))"
- It looks like that with the LIMIT 1, Postgres tries to sort the 122 million records table first, which obviously is not going to be very fast.
- If I add an extra (seemingly redundant) WHERE clause to the query, then on 9.1 the query is fast again, but unfortunately not on 9.2. With the WHERE and LIMIT clauses the query is:
- SELECT
- *
- FROM
- stream_store
- JOIN
- (
- SELECT
- UNNEST(stream_store_ids) AS id
- FROM
- stream_store_version_index
- WHERE
- stream_id = 607106 AND
- version = 11
- ) AS records USING (id)
- WHERE
- stream_store.stream_id = 607106
- ORDER BY
- id DESC
- LIMIT 1
- Postgres 9.1 comes up with the following plan for the above query, which is pretty fast:
- "Limit (cost=25.57..25.58 rows=1 width=1189) (actual time=27.116..27.117 rows=1 loops=1)"
- " -> Sort (cost=25.57..26.45 rows=349 width=1189) (actual time=27.115..27.115 rows=1 loops=1)"
- " Sort Key: public.stream_store.id"
- " Sort Method: top-N heapsort Memory: 25kB"
- " -> Nested Loop (cost=0.00..23.83 rows=349 width=1189) (actual time=26.639..27.062 rows=27 loops=1)"
- " Join Filter: (public.stream_store.id = (unnest(stream_store_version_index.stream_store_ids)))"
- " -> Index Scan using stream_store_version_index_unique_idx on stream_store_version_index (cost=0.00..2.67 rows=1 width=383) (actual time=0.363..0.373 rows=27 loops=1)"
- " Index Cond: ((stream_id = 607106) AND (version = 11))"
- " -> Append (cost=0.00..21.06 rows=7 width=1296) (actual time=0.981..0.986 rows=1 loops=27)"
- " -> Seq Scan on stream_store (cost=0.00..0.00 rows=1 width=1385) (actual time=0.000..0.000 rows=0 loops=27)"
- " Filter: (stream_id = 607106)"
- " -> Index Scan using stream_store_slice0_stream_id on stream_store_slice0 stream_store (cost=0.00..2.67 rows=1 width=1385) (actual time=0.001..0.001 rows=0 loops=27)"
- " Index Cond: (stream_id = 607106)"
- " -> Index Scan using stream_store_slice1_stream_id on stream_store_slice1 stream_store (cost=0.00..2.67 rows=1 width=1385) (actual time=0.001..0.001 rows=0 loops=27)"
- " Index Cond: (stream_id = 607106)"
- " -> Index Scan using stream_store_slice2_id on stream_store_slice2 stream_store (cost=0.00..4.93 rows=1 width=1179) (actual time=0.002..0.002 rows=0 loops=27)"
- " Index Cond: (id = (unnest(stream_store_version_index.stream_store_ids)))"
- " Filter: (stream_id = 607106)"
- " -> Index Scan using stream_store_slice3_id on stream_store_slice3 stream_store (cost=0.00..3.95 rows=1 width=1244) (actual time=0.976..0.977 rows=1 loops=27)"
- " Index Cond: (id = (unnest(stream_store_version_index.stream_store_ids)))"
- " Filter: (stream_id = 607106)"
- " -> Index Scan using stream_store_slice4_id on stream_store_slice4 stream_store (cost=0.00..4.16 rows=1 width=1110) (actual time=0.003..0.003 rows=0 loops=27)"
- " Index Cond: (id = (unnest(stream_store_version_index.stream_store_ids)))"
- " Filter: (stream_id = 607106)"
- " -> Index Scan using stream_store_slice5_stream_id on stream_store_slice5 stream_store (cost=0.00..2.67 rows=1 width=1385) (actual time=0.001..0.001 rows=0 loops=27)"
- " Index Cond: (stream_id = 607106)"
- Postgres 9.2 is different though, but this is also a different machine and it has a different snapshot of the database data. The full version string of this 9.2 machine is "PostgreSQL 9.2.0 on x86_64-unknown-linux-gnu, compiled by gcc (Debian 4.7.1-7) 4.7.1, 64-bit". It has a single E5-1620 3.6-3.8GHz CPU, 32GB of memory, and an LSI 9625 with 8 Samsung 830 SSDs in RAID 6. The "stream_store" table has 114 million rows and is again partitioned. The array that's being unnested for the join still has 27 entries.
- In this case, for the query with the extra WHERE clause and the LIMIT clause the following plan is created:
- "Limit (cost=0.11..3148.54 rows=1 width=1197)"
- " -> Nested Loop (cost=0.11..102720878.16 rows=32626 width=1197)"
- " Join Filter: (public.stream_store.id = (unnest(stream_store_version_index.stream_store_ids)))"
- " -> Merge Append (cost=0.11..102622993.83 rows=65253 width=1197)"
- " Sort Key: public.stream_store.id"
- " -> Sort (cost=0.01..0.02 rows=1 width=1385)"
- " Sort Key: public.stream_store.id"
- " -> Seq Scan on stream_store (cost=0.00..0.00 rows=1 width=1385)"
- " Filter: (stream_id = 607106)"
- " -> Index Scan Backward using stream_store_slice0_id on stream_store_slice0 stream_store (cost=0.00..52.93 rows=1 width=1385)"
- " Filter: (stream_id = 607106)"
- " -> Index Scan Backward using stream_store_slice1_id on stream_store_slice1 stream_store (cost=0.00..52.93 rows=1 width=1385)"
- " Filter: (stream_id = 607106)"
- " -> Index Scan Backward using stream_store_slice2_id on stream_store_slice2 stream_store (cost=0.00..63486684.41 rows=40081 width=1187)"
- " Filter: (stream_id = 607106)"
- " -> Index Scan Backward using stream_store_slice3_id on stream_store_slice3 stream_store (cost=0.00..36776078.12 rows=20576 width=1250)"
- " Filter: (stream_id = 607106)"
- " -> Index Scan Backward using stream_store_slice4_id on stream_store_slice4 stream_store (cost=0.00..2358077.39 rows=4592 width=1045)"
- " Filter: (stream_id = 607106)"
- " -> Index Scan Backward using stream_store_slice5_id on stream_store_slice5 stream_store (cost=0.00..52.93 rows=1 width=1385)"
- " Filter: (stream_id = 607106)"
- " -> Materialize (cost=0.00..5.08 rows=100 width=8)"
- " -> Index Scan using stream_store_version_index_unique_idx on stream_store_version_index (cost=0.00..3.58 rows=100 width=386)"
- " Index Cond: ((stream_id = 607106) AND (version = 11))"
- This is the version again where PG seems to sort the entire stream_store table first, which is incredibly slow.
- Out of pure desperation, I also tried the following really redundant query on 9.2, and this is one fast again:
- SELECT
- *
- FROM
- stream_store
- JOIN
- (
- SELECT
- UNNEST(stream_store_ids) AS id
- FROM
- stream_store_version_index
- WHERE
- stream_id = 607106 AND
- version = 11
- ) AS records USING (id)
- WHERE
- stream_store.stream_id = 607106 AND
- stream_store.id IN (
- SELECT
- UNNEST(stream_store_ids)
- FROM
- stream_store_version_index
- WHERE
- stream_id = 607106 AND
- version = 27
- ORDER BY
- id DESC
- )
- ORDER BY
- id DESC
- LIMIT 1
- In this case PG 9.2 comes up with the following plan:
- "Limit (cost=20.62..20.99 rows=1 width=1197) (actual time=0.053..0.053 rows=0 loops=1)"
- " -> Nested Loop (cost=20.62..5978.93 rows=16313 width=1197) (actual time=0.053..0.053 rows=0 loops=1)"
- " -> Merge Join (cost=20.62..22.62 rows=100 width=16) (actual time=0.052..0.052 rows=0 loops=1)"
- " Merge Cond: ((unnest(public.stream_store_version_index.stream_store_ids)) = (unnest(public.stream_store_version_index.stream_store_ids)))"
- " -> Sort (cost=7.90..8.15 rows=100 width=8) (actual time=0.039..0.039 rows=1 loops=1)"
- " Sort Key: (unnest(public.stream_store_version_index.stream_store_ids))"
- " Sort Method: quicksort Memory: 26kB"
- " -> Index Scan using stream_store_version_index_unique_idx on stream_store_version_index (cost=0.00..3.58 rows=100 width=386) (actual time=0.021..0.023 rows=27 loops=1)"
- " Index Cond: ((stream_id = 607106) AND (version = 11))"
- " -> Sort (cost=12.72..12.97 rows=100 width=8) (actual time=0.012..0.012 rows=0 loops=1)"
- " Sort Key: (unnest(public.stream_store_version_index.stream_store_ids))"
- " Sort Method: quicksort Memory: 25kB"
- " -> HashAggregate (cost=8.40..9.40 rows=100 width=8) (actual time=0.006..0.006 rows=0 loops=1)"
- " -> Sort (cost=6.90..7.15 rows=100 width=394) (actual time=0.005..0.005 rows=0 loops=1)"
- " Sort Key: public.stream_store_version_index.id"
- " Sort Method: quicksort Memory: 25kB"
- " -> Index Scan using stream_store_version_index_unique_idx on stream_store_version_index (cost=0.00..3.58 rows=100 width=394) (actual time=0.002..0.002 rows=0 loops=1)"
- " Index Cond: ((stream_id = 607106) AND (version = 27))"
- " -> Append (cost=0.00..59.49 rows=7 width=1289) (never executed)"
- " -> Seq Scan on stream_store (cost=0.00..0.00 rows=1 width=1385) (never executed)"
- " Filter: ((stream_id = 607106) AND ((unnest(public.stream_store_version_index.stream_store_ids)) = id))"
- " -> Index Scan using stream_store_slice0_id on stream_store_slice0 stream_store (cost=0.00..1.28 rows=1 width=1385) (never executed)"
- " Index Cond: (id = (unnest(public.stream_store_version_index.stream_store_ids)))"
- " Filter: (stream_id = 607106)"
- " -> Index Scan using stream_store_slice1_id on stream_store_slice1 stream_store (cost=0.00..1.28 rows=1 width=1385) (never executed)"
- " Index Cond: (id = (unnest(public.stream_store_version_index.stream_store_ids)))"
- " Filter: (stream_id = 607106)"
- " -> Index Scan using stream_store_slice2_id on stream_store_slice2 stream_store (cost=0.00..29.45 rows=1 width=1187) (never executed)"
- " Index Cond: (id = (unnest(public.stream_store_version_index.stream_store_ids)))"
- " Filter: (stream_id = 607106)"
- " -> Index Scan using stream_store_slice3_id on stream_store_slice3 stream_store (cost=0.00..18.02 rows=1 width=1250) (never executed)"
- " Index Cond: (id = (unnest(public.stream_store_version_index.stream_store_ids)))"
- " Filter: (stream_id = 607106)"
- " -> Index Scan using stream_store_slice4_id on stream_store_slice4 stream_store (cost=0.00..8.18 rows=1 width=1045) (never executed)"
- " Index Cond: (id = (unnest(public.stream_store_version_index.stream_store_ids)))"
- " Filter: (stream_id = 607106)"
- " -> Index Scan using stream_store_slice5_id on stream_store_slice5 stream_store (cost=0.00..1.28 rows=1 width=1385) (never executed)"
- " Index Cond: (id = (unnest(public.stream_store_version_index.stream_store_ids)))"
- " Filter: (stream_id = 607106)"
- "Total runtime: 0.185 ms"
- I tried some variations of the above query with only the IN, or the IN and the extra WHERE, but only the version with both the JOIN and the IN is fast again.
- Is there anything I can do to make the query fast again with the LIMIT on both 9.1 and 9.2 without having to specify so much duplicate constraints?
- Thanks in advance
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement