BUG #13640: Delete isn't using available Index Only Scan - Mailing list pgsql-bugs

From finzelj@gmail.com
Subject BUG #13640: Delete isn't using available Index Only Scan
Date
Msg-id 20150925183859.26929.93860@wrigleys.postgresql.org
Whole thread Raw
Responses Re: BUG #13640: Delete isn't using available Index Only Scan  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-bugs
The following bug has been logged on the website:

Bug reference:      13640
Logged by:          Jeremy Finzel
Email address:      finzelj@gmail.com
PostgreSQL version: 9.3.9
Operating system:   Linux
Description:

I have a query running in Postgres 9.3.9 where I want to delete some records
from a temp table based on using an EXISTS clause that matches a specific
partial index condition I created. The following related query uses an Index
Only Scan on this partial index (abbreviated as 'conditions' below):

EXPLAIN
SELECT l.id
FROM temp_table l
WHERE NOT EXISTS
        (SELECT 1
          FROM customers cx
          WHERE cx.id = l.customer_id
            AND ( conditions ));

                                          QUERY PLAN

----------------------------------------------------------------------------------------------
 Nested Loop Anti Join  (cost=0.42..252440.38 rows=43549 width=4)
   ->  Seq Scan on temp_table l  (cost=0.00..1277.98 rows=87098 width=8)
   ->  Index Only Scan using customers__bad on customers cx
(cost=0.42..3.35     rows=1 width=4)
         Index Cond: (id = l.customer_id)
(4 rows)

Here is the actual delete query SQL. This doesn't but I am convinced should
use the same Index Only Scan as above, and I wonder if it's a bug? Notice
the higher cost:

DELETE
  FROM temp_table l
  WHERE EXISTS(SELECT 1
          FROM cnu.customers cx
          WHERE cx.id = l.customer_id
            AND ( conditions ));


                                           QUERY PLAN

------------------------------------------------------------------------------------------------
 Delete on temp_table l  (cost=0.42..495426.94 rows=43549 width=12)
   ->  Nested Loop Semi Join  (cost=0.42..495426.94 rows=43549 width=12)
         ->  Seq Scan on temp_table l  (cost=0.00..1277.98 rows=87098
width=10)
         ->  Index Scan using customers__bad on customers cx
(cost=0.42..6.67 rows=1 width=10)
               Index Cond: (id = l.customer_id)
(5 rows)

To show that it should be possible on delete to get the same plan, I had to
do this, and it gave me the plan I wanted, and was twice as fast as the
query above that uses an Index Scan instead of Index Only Scan:

WITH the_right_records AS
(SELECT l.id
FROM temp_table l
WHERE NOT EXISTS
        (SELECT 1
          FROM cnu.customers cx
          WHERE cx.id = l.customer_id
            AND ( conditions ))

DELETE FROM temp_table t
WHERE NOT EXISTS (SELECT 1
                  FROM the_right_records x
                  WHERE x.id = t.id);

                                              QUERY PLAN

------------------------------------------------------------------------------------------------------
 Delete on temp_table t  (cost=253855.72..256902.88 rows=43549 width=34)
   CTE the_right_records
     ->  Nested Loop Anti Join  (cost=0.42..252440.38 rows=43549 width=4)
           ->  Seq Scan on temp_table l  (cost=0.00..1277.98 rows=87098
width=8)
           ->  Index Only Scan using customers__bad on customers cx
(cost=0.42..3.35 rows=1 width=4)
                 Index Cond: (id = l.customer_id)
   ->  Hash Anti Join  (cost=1415.34..4462.50 rows=43549 width=34)
         Hash Cond: (t.id = x.id)
         ->  Seq Scan on temp_table t  (cost=0.00..1277.98 rows=87098
width=10)
         ->  Hash  (cost=870.98..870.98 rows=43549 width=32)
               ->  CTE Scan on the_right_records x  (cost=0.00..870.98
rows=43549 width=32)
(11 rows)

I've noticed this same behavior in other examples.

Thank you.

pgsql-bugs by date:

Previous
From: Tom Lane
Date:
Subject: Re: BUG #13638: Exception texts from plperl has bad encoding
Next
From: Michal Leinweber
Date:
Subject: Re: BUG #13638: Exception texts from plperl has bad encoding