@ -39,7 +39,7 @@
<para>
<para>
Examples in this section are drawn from the regression test database
Examples in this section are drawn from the regression test database
after doing a <command>VACUUM ANALYZE</command>, using 9.3 development sources.
after doing a <command>VACUUM ANALYZE</command>, using v17 development sources.
You should be able to get similar results if you try the examples
You should be able to get similar results if you try the examples
yourself, but your estimated costs and row counts might vary slightly
yourself, but your estimated costs and row counts might vary slightly
because <command>ANALYZE</command>'s statistics are random samples rather
because <command>ANALYZE</command>'s statistics are random samples rather
@ -88,7 +88,7 @@ EXPLAIN SELECT * FROM tenk1;
QUERY PLAN
QUERY PLAN
-------------------------------------------------------------
-------------------------------------------------------------
Seq Scan on tenk1 (cost=0.00..458 .00 rows=10000 width=244)
Seq Scan on tenk1 (cost=0.00..44 5.00 rows=10000 width=244)
</screen>
</screen>
</para>
</para>
@ -169,7 +169,7 @@ EXPLAIN SELECT * FROM tenk1;
QUERY PLAN
QUERY PLAN
-------------------------------------------------------------
-------------------------------------------------------------
Seq Scan on tenk1 (cost=0.00..458 .00 rows=10000 width=244)
Seq Scan on tenk1 (cost=0.00..44 5.00 rows=10000 width=244)
</screen>
</screen>
</para>
</para>
@ -180,12 +180,12 @@ EXPLAIN SELECT * FROM tenk1;
SELECT relpages, reltuples FROM pg_class WHERE relname = 'tenk1';
SELECT relpages, reltuples FROM pg_class WHERE relname = 'tenk1';
</programlisting>
</programlisting>
you will find that <classname>tenk1</classname> has 358 disk
you will find that <classname>tenk1</classname> has 34 5 disk
pages and 10000 rows. The estimated cost is computed as (disk pages read *
pages and 10000 rows. The estimated cost is computed as (disk pages read *
<xref linkend="guc-seq-page-cost"/>) + (rows scanned *
<xref linkend="guc-seq-page-cost"/>) + (rows scanned *
<xref linkend="guc-cpu-tuple-cost"/>). By default,
<xref linkend="guc-cpu-tuple-cost"/>). By default,
<varname>seq_page_cost</varname> is 1.0 and <varname>cpu_tuple_cost</varname> is 0.01,
<varname>seq_page_cost</varname> is 1.0 and <varname>cpu_tuple_cost</varname> is 0.01,
so the estimated cost is (358 * 1.0) + (10000 * 0.01) = 458 .
so the estimated cost is (34 5 * 1.0) + (10000 * 0.01) = 44 5.
</para>
</para>
<para>
<para>
@ -196,7 +196,7 @@ EXPLAIN SELECT * FROM tenk1 WHERE unique1 < 7000;
QUERY PLAN
QUERY PLAN
------------------------------------------------------------
------------------------------------------------------------
Seq Scan on tenk1 (cost=0.00..483.00 rows=7001 width=244)
Seq Scan on tenk1 (cost=0.00..470.00 rows=7000 width=244)
Filter: (unique1 < 7000)
Filter: (unique1 < 7000)
</screen>
</screen>
@ -216,7 +216,7 @@ EXPLAIN SELECT * FROM tenk1 WHERE unique1 < 7000;
<para>
<para>
The actual number of rows this query would select is 7000, but the <literal>rows</literal>
The actual number of rows this query would select is 7000, but the <literal>rows</literal>
estimate is only approximate. If you try to duplicate this experiment,
estimate is only approximate. If you try to duplicate this experiment,
you will probably get a slightly different estimate; moreover, it can
you may well get a slightly different estimate; moreover, it can
change after each <command>ANALYZE</command> command, because the
change after each <command>ANALYZE</command> command, because the
statistics produced by <command>ANALYZE</command> are taken from a
statistics produced by <command>ANALYZE</command> are taken from a
randomized sample of the table.
randomized sample of the table.
@ -230,9 +230,9 @@ EXPLAIN SELECT * FROM tenk1 WHERE unique1 < 100;
QUERY PLAN
QUERY PLAN
-------------------------------------------------------------------&zwsp;-----------
-------------------------------------------------------------------&zwsp;-----------
Bitmap Heap Scan on tenk1 (cost=5.07..229.20 rows=101 width=244)
Bitmap Heap Scan on tenk1 (cost=5.06..224.98 rows=100 width=244)
Recheck Cond: (unique1 < 100)
Recheck Cond: (unique1 < 100)
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..5.04 rows=101 width=0)
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..5.04 rows=100 width=0)
Index Cond: (unique1 < 100)
Index Cond: (unique1 < 100)
</screen>
</screen>
@ -257,19 +257,19 @@ EXPLAIN SELECT * FROM tenk1 WHERE unique1 < 100 AND stringu1 = 'xxx';
QUERY PLAN
QUERY PLAN
-------------------------------------------------------------------&zwsp;-----------
-------------------------------------------------------------------&zwsp;-----------
Bitmap Heap Scan on tenk1 (cost=5.04..229.43 rows=1 width=244)
Bitmap Heap Scan on tenk1 (cost=5.04..225.20 rows=1 width=244)
Recheck Cond: (unique1 < 100)
Recheck Cond: (unique1 < 100)
Filter: (stringu1 = 'xxx'::name)
Filter: (stringu1 = 'xxx'::name)
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..5.04 rows=101 width=0)
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..5.04 rows=100 width=0)
Index Cond: (unique1 < 100)
Index Cond: (unique1 < 100)
</screen>
</screen>
The added condition <literal>stringu1 = 'xxx'</literal> reduces the
The added condition <literal>stringu1 = 'xxx'</literal> reduces the
output row count estimate, but not the cost because we still have to visit
output row count estimate, but not the cost because we still have to visit
the same set of rows. Notice that the <literal>stringu1</literal> clause
the same set of rows. That's because the <literal>stringu1</literal> clause
cannot be applied as an index condition, since this index is only on
cannot be applied as an index condition, since this index is only on
the <literal>unique1</literal> column. Instead it is applied as a filter on
the <literal>unique1</literal> column. Instead it is applied as a filter on
the rows retrieved by the index. Thus the cost has actually gone up
the rows retrieved using the index. Thus the cost has actually gone up
slightly to reflect this extra checking.
slightly to reflect this extra checking.
</para>
</para>
@ -300,10 +300,11 @@ EXPLAIN SELECT * FROM tenk1 WHERE unique1 = 42;
The planner may implement an <literal>ORDER BY</literal> clause in several
The planner may implement an <literal>ORDER BY</literal> clause in several
ways. The above example shows that such an ordering clause may be
ways. The above example shows that such an ordering clause may be
implemented implicitly. The planner may also add an explicit
implemented implicitly. The planner may also add an explicit
<literal>s ort</literal> step:
<literal>S ort</literal> step:
<screen>
<screen>
EXPLAIN SELECT * FROM tenk1 ORDER BY unique1;
EXPLAIN SELECT * FROM tenk1 ORDER BY unique1;
QUERY PLAN
QUERY PLAN
-------------------------------------------------------------------
-------------------------------------------------------------------
Sort (cost=1109.39..1134.39 rows=10000 width=244)
Sort (cost=1109.39..1134.39 rows=10000 width=244)
@ -313,17 +314,18 @@ EXPLAIN SELECT * FROM tenk1 ORDER BY unique1;
If a part of the plan guarantees an ordering on a prefix of the
If a part of the plan guarantees an ordering on a prefix of the
required sort keys, then the planner may instead decide to use an
required sort keys, then the planner may instead decide to use an
<literal>incremental s ort</literal> step:
<literal>Incremental S ort</literal> step:
<screen>
<screen>
EXPLAIN SELECT * FROM tenk1 ORDER BY four, ten LIMIT 100;
EXPLAIN SELECT * FROM tenk1 ORDER BY hundred, ten LIMIT 100;
QUERY PLAN
QUERY PLAN
-------------------------------------------------------------------&zwsp;-----------------------------------
-------------------------------------------------------------------&zwsp;-----------------------------
Limit (cost=521.06..538.05 rows=100 width=244)
Limit (cost=19.35..39.49 rows=100 width=244)
-> Incremental Sort (cost=521.06..2220.95 rows=10000 width=244)
-> Incremental Sort (cost=19.35..2033.39 rows=10000 width=244)
Sort Key: four , ten
Sort Key: hundred , ten
Presorted Key: four
Presorted Key: hundred
-> Index Scan using index_tenk1_on_four on tenk1 (cost=0.29..1510.08 rows=10000 width=244)
-> Index Scan using tenk1_hundred on tenk1 (cost=0.29..1574.20 rows=10000 width=244)
</screen>
</screen>
Compared to regular sorts, sorting incrementally allows returning tuples
Compared to regular sorts, sorting incrementally allows returning tuples
@ -344,10 +346,10 @@ EXPLAIN SELECT * FROM tenk1 WHERE unique1 < 100 AND unique2 > 9000;
QUERY PLAN
QUERY PLAN
-------------------------------------------------------------------&zwsp;------------------
-------------------------------------------------------------------&zwsp;------------------
Bitmap Heap Scan on tenk1 (cost=25.08..60.2 1 rows=10 width=244)
Bitmap Heap Scan on tenk1 (cost=25.07..60.1 1 rows=10 width=244)
Recheck Cond: ((unique1 < 100) AND (unique2 > 9000))
Recheck Cond: ((unique1 < 100) AND (unique2 > 9000))
-> BitmapAnd (cost=25.08..25.08 rows=10 width=0)
-> BitmapAnd (cost=25.07..25.07 rows=10 width=0)
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..5.04 rows=101 width=0)
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..5.04 rows=100 width=0)
Index Cond: (unique1 < 100)
Index Cond: (unique1 < 100)
-> Bitmap Index Scan on tenk1_unique2 (cost=0.00..19.78 rows=999 width=0)
-> Bitmap Index Scan on tenk1_unique2 (cost=0.00..19.78 rows=999 width=0)
Index Cond: (unique2 > 9000)
Index Cond: (unique2 > 9000)
@ -367,8 +369,8 @@ EXPLAIN SELECT * FROM tenk1 WHERE unique1 < 100 AND unique2 > 9000 LIMIT 2
QUERY PLAN
QUERY PLAN
-------------------------------------------------------------------&zwsp;------------------
-------------------------------------------------------------------&zwsp;------------------
Limit (cost=0.29..14.4 8 rows=2 width=244)
Limit (cost=0.29..14.2 8 rows=2 width=244)
-> Index Scan using tenk1_unique2 on tenk1 (cost=0.29..71 .27 rows=10 width=244)
-> Index Scan using tenk1_unique2 on tenk1 (cost=0.29..70 .27 rows=10 width=244)
Index Cond: (unique2 > 9000)
Index Cond: (unique2 > 9000)
Filter: (unique1 < 100)
Filter: (unique1 < 100)
</screen>
</screen>
@ -397,12 +399,12 @@ WHERE t1.unique1 < 10 AND t1.unique2 = t2.unique2;
QUERY PLAN
QUERY PLAN
-------------------------------------------------------------------&zwsp;-------------------
-------------------------------------------------------------------&zwsp;-------------------
Nested Loop (cost=4.65..118.62 rows=10 width=488)
Nested Loop (cost=4.65..118.50 rows=10 width=488)
-> Bitmap Heap Scan on tenk1 t1 (cost=4.36..39.47 rows=10 width=244)
-> Bitmap Heap Scan on tenk1 t1 (cost=4.36..39.38 rows=10 width=244)
Recheck Cond: (unique1 < 10)
Recheck Cond: (unique1 < 10)
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..4.36 rows=10 width=0)
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..4.36 rows=10 width=0)
Index Cond: (unique1 < 10)
Index Cond: (unique1 < 10)
-> Index Scan using tenk2_unique2 on tenk2 t2 (cost=0.29..7.91 rows=1 width=244)
-> Index Scan using tenk2_unique2 on tenk2 t2 (cost=0.29..7.90 rows=1 width=244)
Index Cond: (unique2 = t1.unique2)
Index Cond: (unique2 = t1.unique2)
</screen>
</screen>
</para>
</para>
@ -428,7 +430,7 @@ WHERE t1.unique1 < 10 AND t1.unique2 = t2.unique2;
as a result of caching that's expected to occur during the repeated
as a result of caching that's expected to occur during the repeated
index scans on <literal>t2</literal>.) The
index scans on <literal>t2</literal>.) The
costs of the loop node are then set on the basis of the cost of the outer
costs of the loop node are then set on the basis of the cost of the outer
scan, plus one repetition of the inner scan for each outer row (10 * 7.91 ,
scan, plus one repetition of the inner scan for each outer row (10 * 7.90 ,
here), plus a little CPU time for join processing.
here), plus a little CPU time for join processing.
</para>
</para>
@ -446,9 +448,9 @@ WHERE t1.unique1 < 10 AND t2.unique2 < 10 AND t1.hundred < t2.hundred;
QUERY PLAN
QUERY PLAN
-------------------------------------------------------------------&zwsp;--------------------------
-------------------------------------------------------------------&zwsp;--------------------------
Nested Loop (cost=4.65..49.4 6 rows=33 width=488)
Nested Loop (cost=4.65..49.3 6 rows=33 width=488)
Join Filter: (t1.hundred < t2.hundred)
Join Filter: (t1.hundred < t2.hundred)
-> Bitmap Heap Scan on tenk1 t1 (cost=4.36..39.47 rows=10 width=244)
-> Bitmap Heap Scan on tenk1 t1 (cost=4.36..39.38 rows=10 width=244)
Recheck Cond: (unique1 < 10)
Recheck Cond: (unique1 < 10)
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..4.36 rows=10 width=0)
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..4.36 rows=10 width=0)
Index Cond: (unique1 < 10)
Index Cond: (unique1 < 10)
@ -494,13 +496,13 @@ WHERE t1.unique1 < 100 AND t1.unique2 = t2.unique2;
QUERY PLAN
QUERY PLAN
-------------------------------------------------------------------&zwsp;-----------------------
-------------------------------------------------------------------&zwsp;-----------------------
Hash Join (cost=230.47..713.98 rows=101 width=488)
Hash Join (cost=226.23..709.73 rows=100 width=488)
Hash Cond: (t2.unique2 = t1.unique2)
Hash Cond: (t2.unique2 = t1.unique2)
-> Seq Scan on tenk2 t2 (cost=0.00..445.00 rows=10000 width=244)
-> Seq Scan on tenk2 t2 (cost=0.00..445.00 rows=10000 width=244)
-> Hash (cost=229.20..229.20 rows=101 width=244)
-> Hash (cost=224.98..224.98 rows=100 width=244)
-> Bitmap Heap Scan on tenk1 t1 (cost=5.07..229.20 rows=101 width=244)
-> Bitmap Heap Scan on tenk1 t1 (cost=5.06..224.98 rows=100 width=244)
Recheck Cond: (unique1 < 100)
Recheck Cond: (unique1 < 100)
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..5.04 rows=101 width=0)
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..5.04 rows=100 width=0)
Index Cond: (unique1 < 100)
Index Cond: (unique1 < 100)
</screen>
</screen>
</para>
</para>
@ -525,22 +527,18 @@ WHERE t1.unique1 < 100 AND t1.unique2 = t2.unique2;
QUERY PLAN
QUERY PLAN
-------------------------------------------------------------------&zwsp;-----------------------
-------------------------------------------------------------------&zwsp;-----------------------
Merge Join (cost=198.11..268.1 9 rows=10 width=488)
Merge Join (cost=0.56..233.4 9 rows=10 width=488)
Merge Cond: (t1.unique2 = t2.unique2)
Merge Cond: (t1.unique2 = t2.unique2)
-> Index Scan using tenk1_unique2 on tenk1 t1 (cost=0.29..656.28 rows=101 width=244)
-> Index Scan using tenk1_unique2 on tenk1 t1 (cost=0.29..643.28 rows=100 width=244)
Filter: (unique1 < 100)
Filter: (unique1 < 100)
-> Sort (cost=197.83..200.33 rows=1000 width=244)
-> Index Scan using onek_unique2 on onek t2 (cost=0.28..166.28 rows=1000 width=244)
Sort Key: t2.unique2
-> Seq Scan on onek t2 (cost=0.00..148.00 rows=1000 width=244)
</screen>
</screen>
</para>
</para>
<para>
<para>
Merge join requires its input data to be sorted on the join keys. In this
Merge join requires its input data to be sorted on the join keys. In this
plan the <literal>tenk1</literal> data is sorted by using an index scan to visit
example each input is sorted by using an index scan to visit the rows
the rows in the correct order, but a sequential scan and sort is preferred
in the correct order; but a sequential scan and sort could also be used.
for <literal>onek</literal>, because there are many more rows to be visited in
that table.
(Sequential-scan-and-sort frequently beats an index scan for sorting many rows,
(Sequential-scan-and-sort frequently beats an index scan for sorting many rows,
because of the nonsequential disk access required by the index scan.)
because of the nonsequential disk access required by the index scan.)
</para>
</para>
@ -551,11 +549,11 @@ WHERE t1.unique1 < 100 AND t1.unique2 = t2.unique2;
flags described in <xref linkend="runtime-config-query-enable"/>.
flags described in <xref linkend="runtime-config-query-enable"/>.
(This is a crude tool, but useful. See
(This is a crude tool, but useful. See
also <xref linkend="explicit-joins"/>.)
also <xref linkend="explicit-joins"/>.)
For example, if we're unconvinced that sequential-scan-and-sort is the best way to
For example, if we're unconvinced that merge join is the best join
deal with table <literal>onek</literal> in the previous example, we could try
type for the previous example, we could try
<screen>
<screen>
SET enable_sort = off;
SET enable_mergejoin = off;
EXPLAIN SELECT *
EXPLAIN SELECT *
FROM tenk1 t1, onek t2
FROM tenk1 t1, onek t2
@ -563,15 +561,18 @@ WHERE t1.unique1 < 100 AND t1.unique2 = t2.unique2;
QUERY PLAN
QUERY PLAN
-------------------------------------------------------------------&zwsp;-----------------------
-------------------------------------------------------------------&zwsp;-----------------------
Merge Join (cost=0.56..292.65 rows=10 width=488)
Hash Join (cost=226.23..344.08 rows=10 width=488)
Merge Cond: (t1.unique2 = t2.unique2)
Hash Cond: (t2.unique2 = t1.unique2)
-> Index Scan using tenk1_unique2 on tenk1 t1 (cost=0.29..656.28 rows=101 width=244)
-> Seq Scan on onek t2 (cost=0.00..114.00 rows=1000 width=244)
Filter: (unique1 < 100)
-> Hash (cost=224.98..224.98 rows=100 width=244)
-> Index Scan using onek_unique2 on onek t2 (cost=0.28..224.79 rows=1000 width=244)
-> Bitmap Heap Scan on tenk1 t1 (cost=5.06..224.98 rows=100 width=244)
Recheck Cond: (unique1 < 100)
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..5.04 rows=100 width=0)
Index Cond: (unique1 < 100)
</screen>
</screen>
which shows that the planner thinks that sorting <literal>onek</literal> by
which shows that the planner thinks that hash join would be nearly 50%
index-scanning is about 12% more expensive than sequential-scan-and-sort .
more expensive than merge join for this case .
Of course, the next question is whether it's right about that.
Of course, the next question is whether it's right about that.
We can investigate that using <command>EXPLAIN ANALYZE</command>, as
We can investigate that using <command>EXPLAIN ANALYZE</command>, as
discussed <link linkend="using-explain-analyze">below</link>.
discussed <link linkend="using-explain-analyze">below</link>.
@ -695,15 +696,16 @@ WHERE t1.unique1 < 10 AND t1.unique2 = t2.unique2;
QUERY PLAN
QUERY PLAN
-------------------------------------------------------------------&zwsp;--------------------------------------------------------------
-------------------------------------------------------------------&zwsp;--------------------------------------------------------------
Nested Loop (cost=4.65..118.62 rows=10 width=488) (actual time=0.128..0.377 rows=10 loops=1)
Nested Loop (cost=4.65..118.50 rows=10 width=488) (actual time=0.017..0.051 rows=10 loops=1)
-> Bitmap Heap Scan on tenk1 t1 (cost=4.36..39.47 rows=10 width=244) (actual time=0.057..0.121 rows=10 loops=1)
-> Bitmap Heap Scan on tenk1 t1 (cost=4.36..39.38 rows=10 width=244) (actual time=0.009..0.017 rows=10 loops=1)
Recheck Cond: (unique1 < 10)
Recheck Cond: (unique1 < 10)
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..4.36 rows=10 width=0) (actual time=0.024..0.024 rows=10 loops=1)
Heap Blocks: exact=10
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..4.36 rows=10 width=0) (actual time=0.004..0.004 rows=10 loops=1)
Index Cond: (unique1 < 10)
Index Cond: (unique1 < 10)
-> Index Scan using tenk2_unique2 on tenk2 t2 (cost=0.29..7.91 rows=1 width=244) (actual time=0.021..0.022 rows=1 loops=10)
-> Index Scan using tenk2_unique2 on tenk2 t2 (cost=0.29..7.90 rows=1 width=244) (actual time=0.003..0.003 rows=1 loops=10)
Index Cond: (unique2 = t1.unique2)
Index Cond: (unique2 = t1.unique2)
Planning time: 0.181 ms
Planning Time: 0.485 ms
Execution time: 0.501 ms
Execution Time: 0.073 ms
</screen>
</screen>
Note that the <quote>actual time</quote> values are in milliseconds of
Note that the <quote>actual time</quote> values are in milliseconds of
@ -723,7 +725,7 @@ WHERE t1.unique1 < 10 AND t1.unique2 = t2.unique2;
values shown are averages per-execution. This is done to make the numbers
values shown are averages per-execution. This is done to make the numbers
comparable with the way that the cost estimates are shown. Multiply by
comparable with the way that the cost estimates are shown. Multiply by
the <literal>loops</literal> value to get the total time actually spent in
the <literal>loops</literal> value to get the total time actually spent in
the node. In the above example, we spent a total of 0.22 0 milliseconds
the node. In the above example, we spent a total of 0.03 0 milliseconds
executing the index scans on <literal>tenk2</literal>.
executing the index scans on <literal>tenk2</literal>.
</para>
</para>
@ -739,20 +741,21 @@ WHERE t1.unique1 < 100 AND t1.unique2 = t2.unique2 ORDER BY t1.fivethous;
QUERY PLAN
QUERY PLAN
-------------------------------------------------------------------&zwsp;-------------------------------------------------------------------&zwsp;------
-------------------------------------------------------------------&zwsp;-------------------------------------------------------------------&zwsp;------
Sort (cost=717.34..717.59 rows=101 width=488) (actual time=7.761..7.774 rows=100 loops=1)
Sort (cost=713.05..713.30 rows=100 width=488) (actual time=2.995..3.002 rows=100 loops=1)
Sort Key: t1.fivethous
Sort Key: t1.fivethous
Sort Method: quicksort Memory: 77 kB
Sort Method: quicksort Memory: 74 kB
-> Hash Join (cost=230.47..713.98 rows=101 width=488) (actual time=0.711..7.427 rows=100 loops=1)
-> Hash Join (cost=226.23..709.73 rows=100 width=488) (actual time=0.515..2.920 rows=100 loops=1)
Hash Cond: (t2.unique2 = t1.unique2)
Hash Cond: (t2.unique2 = t1.unique2)
-> Seq Scan on tenk2 t2 (cost=0.00..445.00 rows=10000 width=244) (actual time=0.007..2.583 rows=10000 loops=1)
-> Seq Scan on tenk2 t2 (cost=0.00..445.00 rows=10000 width=244) (actual time=0.026..1.790 rows=10000 loops=1)
-> Hash (cost=229.20..229.20 rows=101 width=244) (actual time=0.659..0.659 rows=100 loops=1)
-> Hash (cost=224.98..224.98 rows=100 width=244) (actual time=0.476..0.477 rows=100 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 28 kB
Buckets: 1024 Batches: 1 Memory Usage: 35 kB
-> Bitmap Heap Scan on tenk1 t1 (cost=5.07..229.20 rows=101 width=244) (actual time=0.080..0.526 rows=100 loops=1)
-> Bitmap Heap Scan on tenk1 t1 (cost=5.06..224.98 rows=100 width=244) (actual time=0.030..0.450 rows=100 loops=1)
Recheck Cond: (unique1 < 100)
Recheck Cond: (unique1 < 100)
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..5.04 rows=101 width=0) (actual time=0.049..0.049 rows=100 loops=1)
Heap Blocks: exact=90
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..5.04 rows=100 width=0) (actual time=0.013..0.013 rows=100 loops=1)
Index Cond: (unique1 < 100)
Index Cond: (unique1 < 100)
Planning time: 0.194 ms
Planning Time: 0.187 ms
Execution time: 8.008 ms
Execution Time: 3.036 ms
</screen>
</screen>
The Sort node shows the sort method used (in particular, whether the sort
The Sort node shows the sort method used (in particular, whether the sort
@ -772,11 +775,11 @@ EXPLAIN ANALYZE SELECT * FROM tenk1 WHERE ten < 7;
QUERY PLAN
QUERY PLAN
-------------------------------------------------------------------&zwsp;--------------------------------------
-------------------------------------------------------------------&zwsp;--------------------------------------
Seq Scan on tenk1 (cost=0.00..483.00 rows=7000 width=244) (actual time=0.016..5.107 rows=7000 loops=1)
Seq Scan on tenk1 (cost=0.00..470.00 rows=7000 width=244) (actual time=0.030..1.995 rows=7000 loops=1)
Filter: (ten < 7)
Filter: (ten < 7)
Rows Removed by Filter: 3000
Rows Removed by Filter: 3000
Planning time: 0.083 ms
Planning Time: 0.102 ms
Execution time: 5.90 5 ms
Execution Time: 2.14 5 ms
</screen>
</screen>
These counts can be particularly valuable for filter conditions applied at
These counts can be particularly valuable for filter conditions applied at
@ -795,11 +798,11 @@ EXPLAIN ANALYZE SELECT * FROM polygon_tbl WHERE f1 @> polygon '(0.5,2.0)';
QUERY PLAN
QUERY PLAN
-------------------------------------------------------------------&zwsp;-----------------------------------
-------------------------------------------------------------------&zwsp;-----------------------------------
Seq Scan on polygon_tbl (cost=0.00..1.05 rows=1 width=32) (actual time=0.044..0.044 rows=0 loops=1)
Seq Scan on polygon_tbl (cost=0.00..1.09 rows=1 width=85) (actual time=0.023..0.023 rows=0 loops=1)
Filter: (f1 @> '((0.5,2))'::polygon)
Filter: (f1 @> '((0.5,2))'::polygon)
Rows Removed by Filter: 4
Rows Removed by Filter: 7
Planning time: 0.040 ms
Planning Time: 0.039 ms
Execution time: 0.08 3 ms
Execution Time: 0.03 3 ms
</screen>
</screen>
The planner thinks (quite correctly) that this sample table is too small
The planner thinks (quite correctly) that this sample table is too small
@ -814,11 +817,11 @@ EXPLAIN ANALYZE SELECT * FROM polygon_tbl WHERE f1 @> polygon '(0.5,2.0)';
QUERY PLAN
QUERY PLAN
-------------------------------------------------------------------&zwsp;-------------------------------------------------------
-------------------------------------------------------------------&zwsp;-------------------------------------------------------
Index Scan using gpolygonind on polygon_tbl (cost=0.13..8.15 rows=1 width=32) (actual time=0.062..0.062 rows=0 loops=1)
Index Scan using gpolygonind on polygon_tbl (cost=0.13..8.15 rows=1 width=85) (actual time=0.074..0.074 rows=0 loops=1)
Index Cond: (f1 @> '((0.5,2))'::polygon)
Index Cond: (f1 @> '((0.5,2))'::polygon)
Rows Removed by Index Recheck: 1
Rows Removed by Index Recheck: 1
Planning time: 0.034 ms
Planning Time: 0.039 ms
Execution time: 0.144 ms
Execution Time: 0.098 ms
</screen>
</screen>
Here we can see that the index returned one candidate row, which was
Here we can see that the index returned one candidate row, which was
@ -837,19 +840,22 @@ EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM tenk1 WHERE unique1 < 100 AND unique
QUERY PLAN
QUERY PLAN
-------------------------------------------------------------------&zwsp;--------------------------------------------------------------
-------------------------------------------------------------------&zwsp;--------------------------------------------------------------
Bitmap Heap Scan on tenk1 (cost=25.08..60.21 rows=10 width=244) (actual time=0.323..0.342 rows=10 loops=1)
Bitmap Heap Scan on tenk1 (cost=25.07..60.11 rows=10 width=244) (actual time=0.105..0.114 rows=10 loops=1)
Recheck Cond: ((unique1 < 100) AND (unique2 > 9000))
Recheck Cond: ((unique1 < 100) AND (unique2 > 9000))
Buffers: shared hit=15
Heap Blocks: exact=10
-> BitmapAnd (cost=25.08..25.08 rows=10 width=0) (actual time=0.309..0.309 rows=0 loops=1)
Buffers: shared hit=14 read=3
Buffers: shared hit=7
-> BitmapAnd (cost=25.07..25.07 rows=10 width=0) (actual time=0.100..0.101 rows=0 loops=1)
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..5.04 rows=101 width=0) (actual time=0.043..0.043 rows=100 loops=1)
Buffers: shared hit=4 read=3
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..5.04 rows=100 width=0) (actual time=0.027..0.027 rows=100 loops=1)
Index Cond: (unique1 < 100)
Index Cond: (unique1 < 100)
Buffers: shared hit=2
Buffers: shared hit=2
-> Bitmap Index Scan on tenk1_unique2 (cost=0.00..19.78 rows=999 width=0) (actual time=0.227..0.227 rows=999 loops=1)
-> Bitmap Index Scan on tenk1_unique2 (cost=0.00..19.78 rows=999 width=0) (actual time=0.070..0.070 rows=999 loops=1)
Index Cond: (unique2 > 9000)
Index Cond: (unique2 > 9000)
Buffers: shared hit=5
Buffers: shared hit=2 read=3
Planning time: 0.088 ms
Planning:
Execution time: 0.423 ms
Buffers: shared hit=3
Planning Time: 0.162 ms
Execution Time: 0.143 ms
</screen>
</screen>
The numbers provided by <literal>BUFFERS</literal> help to identify which parts
The numbers provided by <literal>BUFFERS</literal> help to identify which parts
@ -871,14 +877,14 @@ EXPLAIN ANALYZE UPDATE tenk1 SET hundred = hundred + 1 WHERE unique1 < 100;
QUERY PLAN
QUERY PLAN
-------------------------------------------------------------------&zwsp;-------------------------------------------------------------
-------------------------------------------------------------------&zwsp;-------------------------------------------------------------
Update on tenk1 (cost=5.08..230.08 rows=0 width=0) (actual time=3.791..3.792 rows=0 loops=1)
Update on tenk1 (cost=5.06..225.23 rows=0 width=0) (actual time=1.634..1.635 rows=0 loops=1)
-> Bitmap Heap Scan on tenk1 (cost=5.08..230.08 rows=102 width=10) (actual time=0.069..0.513 rows=100 loops=1)
-> Bitmap Heap Scan on tenk1 (cost=5.06..225.23 rows=100 width=10) (actual time=0.065..0.141 rows=100 loops=1)
Recheck Cond: (unique1 < 100)
Recheck Cond: (unique1 < 100)
Heap Blocks: exact=90
Heap Blocks: exact=90
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..5.05 rows=102 width=0) (actual time=0.036..0.037 rows=3 00 loops=1)
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..5.04 rows=100 width=0) (actual time=0.031..0.031 rows=1 00 loops=1)
Index Cond: (unique1 < 100)
Index Cond: (unique1 < 100)
Planning Time: 0.113 ms
Planning Time: 0.15 1 ms
Execution Time: 3.850 ms
Execution Time: 1.856 ms
ROLLBACK;
ROLLBACK;
</screen>
</screen>
@ -903,32 +909,30 @@ ROLLBACK;
<para>
<para>
When an <command>UPDATE</command>, <command>DELETE</command>, or
When an <command>UPDATE</command>, <command>DELETE</command>, or
<command>MERGE</command> command affects an
<command>MERGE</command> command affects a partitio ned table or
inheritance hierarchy, the output might look like this:
inheritance hierarchy, the output might look like this:
<screen>
<screen>
EXPLAIN UPDATE parent SET f2 = f2 + 1 WHERE f1 = 101;
EXPLAIN UPDATE gtest_parent SET f1 = CURRENT_DATE WHERE f2 = 101;
QUERY PLAN
-------------------------------------------------------------------&zwsp;-----------------------------------
QUERY PLAN
Update on parent (cost=0.00..24.59 rows=0 width=0)
-------------------------------------------------------------------&zwsp;---------------------
Update on parent parent_1
Update on gtest_parent (cost=0.00..3.06 rows=0 width=0)
Update on child1 parent_2
Update on gtest_child gtest_parent_1
Update on child2 parent_3
Update on gtest_child2 gtest_parent_2
Update on child3 parent_4
Update on gtest_child3 gtest_parent_3
-> Result (cost=0.00..24.59 rows=4 width=14)
-> Append (cost=0.00..3.06 rows=3 width=14)
-> Append (cost=0.00..24.54 rows=4 width=14)
-> Seq Scan on gtest_child gtest_parent_1 (cost=0.00..1.01 rows=1 width=14)
-> Seq Scan on parent parent_1 (cost=0.00..0.00 rows=1 width=14)
Filter: (f2 = 101)
Filter: (f1 = 101)
-> Seq Scan on gtest_child2 gtest_parent_2 (cost=0.00..1.01 rows=1 width=14)
-> Index Scan using child1_pkey on child1 parent_2 (cost=0.15..8.17 rows=1 width=14)
Filter: (f2 = 101)
Index Cond: (f1 = 101)
-> Seq Scan on gtest_child3 gtest_parent_3 (cost=0.00..1.01 rows=1 width=14)
-> Index Scan using child2_pkey on child2 parent_3 (cost=0.15..8.17 rows=1 width=14)
Filter: (f2 = 101)
Index Cond: (f1 = 101)
-> Index Scan using child3_pkey on child3 parent_4 (cost=0.15..8.17 rows=1 width=14)
Index Cond: (f1 = 101)
</screen>
</screen>
In this example the Update node needs to consider three child tables as
In this example the Update node needs to consider three child tables,
well as the originally-mentioned parent table. So there are four input
but not the originally-mentioned partitioned table (since that never
stores any data). So there are three input
scanning subplans, one per table. For clarity, the Update node is
scanning subplans, one per table. For clarity, the Update node is
annotated to show the specific target tables that will be updated, in the
annotated to show the specific target tables that will be updated, in the
same order as the corresponding subplans.
same order as the corresponding subplans.
@ -1010,13 +1014,13 @@ EXPLAIN ANALYZE SELECT * FROM tenk1 WHERE unique1 < 100 AND unique2 > 9000
QUERY PLAN
QUERY PLAN
-------------------------------------------------------------------&zwsp;------------------------------------------------------------
-------------------------------------------------------------------&zwsp;------------------------------------------------------------
Limit (cost=0.29..14.71 rows=2 width=244) (actual time=0.177..0.249 rows=2 loops=1)
Limit (cost=0.29..14.33 rows=2 width=244) (actual time=0.051..0.071 rows=2 loops=1)
-> Index Scan using tenk1_unique2 on tenk1 (cost=0.29..72.42 rows=10 width=244) (actual time=0.174..0.244 rows=2 loops=1)
-> Index Scan using tenk1_unique2 on tenk1 (cost=0.29..70.50 rows=10 width=244) (actual time=0.051..0.070 rows=2 loops=1)
Index Cond: (unique2 > 9000)
Index Cond: (unique2 > 9000)
Filter: (unique1 < 100)
Filter: (unique1 < 100)
Rows Removed by Filter: 287
Rows Removed by Filter: 287
Planning time: 0.096 ms
Planning Time: 0.077 ms
Execution time: 0.33 6 ms
Execution Time: 0.08 6 ms
</screen>
</screen>
the estimated cost and row count for the Index Scan node are shown as
the estimated cost and row count for the Index Scan node are shown as
@ -1097,8 +1101,8 @@ WHERE relname LIKE 'tenk1%';
relname | relkind | reltuples | relpages
relname | relkind | reltuples | relpages
----------------------+---------+-----------+----------
----------------------+---------+-----------+----------
tenk1 | r | 10000 | 358
tenk1 | r | 10000 | 34 5
tenk1_hundred | i | 10000 | 30
tenk1_hundred | i | 10000 | 11
tenk1_thous_tenthous | i | 10000 | 30
tenk1_thous_tenthous | i | 10000 | 30
tenk1_unique1 | i | 10000 | 30
tenk1_unique1 | i | 10000 | 30
tenk1_unique2 | i | 10000 | 30
tenk1_unique2 | i | 10000 | 30
@ -1171,17 +1175,31 @@ WHERE tablename = 'road';
attname | inherited | n_distinct | most_common_vals
attname | inherited | n_distinct | most_common_vals
---------+-----------+------------+------------------------------------
---------+-----------+------------+------------------------------------
name | f | -0.36338 8 | I- 580 Ramp+
name | f | -0.568110 8 | I- 580 Ramp+
| | | I- 880 Ramp+
| | | I- 880 Ramp+
| | | Sp Railroad +
| | | Sp Railroad +
| | | I- 580 +
| | | I- 580 +
| | | I- 680 Ramp
name | t | -0.284859 | I- 880 Ramp+
| | | I- 580 Ramp+
| | | I- 680 Ramp+
| | | I- 680 Ramp+
| | | I- 80 Ramp+
| | | 14th St +
| | | I- 880 +
| | | Mac Arthur Blvd+
| | | Mission Blvd+
...
name | t | -0.5125 | I- 580 Ramp+
| | | I- 880 Ramp+
| | | I- 580 +
| | | I- 580 +
| | | State Hwy 13 Ramp
| | | I- 680 Ramp+
(2 rows)
| | | I- 80 Ramp+
| | | Sp Railroad +
| | | I- 880 +
| | | State Hwy 13 Ramp+
| | | I- 80 +
| | | State Hwy 24 Ramp+
...
thepath | f | 0 |
thepath | t | 0 |
(4 rows)
</screen>
</screen>
Note that two rows are displayed for the same column, one corresponding
Note that two rows are displayed for the same column, one corresponding
@ -1189,6 +1207,8 @@ WHERE tablename = 'road';
<literal>road</literal> table (<literal>inherited</literal>=<literal>t</literal>),
<literal>road</literal> table (<literal>inherited</literal>=<literal>t</literal>),
and another one including only the <literal>road</literal> table itself
and another one including only the <literal>road</literal> table itself
(<literal>inherited</literal>=<literal>f</literal>).
(<literal>inherited</literal>=<literal>f</literal>).
(For brevity, we have only shown the first ten most-common values for
the <literal>name</literal> column.)
</para>
</para>
<para>
<para>