0

I have an update query that goes like this:

update table_1
set col_1='64e27e3e-833e-4d2f-be34-452727e07822'
from table_1 left join table_2 on table_2.id = table_1.id
where
    table_1.col_1='64e27e3e-833e-4d2f-be34-452727e07822'
    and table_1.registered_at between '2022-07-01' and '2022-08-20'
    and table_2.restaurant_id = 158;

There are only 237 records to update, and the following select works instantly:

select * from table_1 left join table_2 on table_2.id = table_1.id
where
    table_1.col_1='64e27e3e-833e-4d2f-be34-452727e07822'
    and table_1.registered_at between '2022-07-01' and '2022-08-20'
    and table_2.restaurant_id = 158;

The longest I've seen this query to run was about 7 minutes. My first guess was that it locks something that is updated during oltp, but when I run this query, pg_locks doesn't reveal any queued (that is, non-granted) locks. Besides, if I set lock_timeout to '1000ms'; the statement continues to run after 1 second passes; so it's not locks. That query terminates only after statement_timeout passes, so it must be the query itself which is executed for so long. And the rows updated in this query are not updated by any other queries -- I intentionally took the records that were registered in the past.

So, what does it take so long?

7
  • Is this a typo or copy & paste error that the value you are setting is identical to the condition in the WHERE clause? Which essentially means the whole UPDATE doesn't change anything
    – user1822
    Commented Aug 24, 2022 at 9:57
  • It's not a typo, I just profile this query on a production database. Commented Aug 24, 2022 at 11:38
  • That makes the statement pretty useless I'd say.
    – user1822
    Commented Aug 24, 2022 at 11:39
  • Uhm, that's the whole point. I don't want to modify any data when I profile queries. So it's useless, but it still hangs Commented Aug 24, 2022 at 11:41
  • To a_horse_with_no_name's point, why waste your time debugging performance of a query you'll never actually use?..unless you saw a similar query with performance problems that you're trying to model? It very well can be the execution plan you're getting for this specific query is just a poor one. You can verify that with running an EXPLAIN ANALYZE with the query. But unless you're trying to solve an actual performance issue of another query by modeling it with this one, the answer to fixing this random query becomes moot because it'll likely involve just rewriting it as another random query.
    – J.D.
    Commented Aug 24, 2022 at 12:32

1 Answer 1

2

Do not repeat the target table in the FROM clause.

Quote from the manual

Do not repeat the target table as a from_item unless you intend a self-join (in which case it must appear with an alias in the from_item).

So you should change that to:

update table_1
  set col_1 = '64e27e3e-833e-4d2f-be34-452727e07822'
from table_2 
where table_2.id = table_1.id
  and table_1.col_1 = '64e27e3e-833e-4d2f-be34-452727e07822'
  and table_1.registered_at between '2022-07-01' and '2022-08-20'
  and table_2.restaurant_id = 158;

The LEFT JOIN you used, isn't really an outer JOIN anyway as your WHERE conditions turn that back into an inner join.

Another option you might want to try is to use an EXISTS condition:

update table_1
  set col_1 = '64e27e3e-833e-4d2f-be34-452727e07822'
from table_2 
where table_1.col_1 = '64e27e3e-833e-4d2f-be34-452727e07822'
  and table_1.registered_at between '2022-07-01' and '2022-08-20'
  and exists (select *
              from table_1
              where table_2.id = table_1.id
                and table_2.restaurant_id = 158);
5
  • Thanks, I tried your suggestions one by one, but still no luck. First, I added an alias to a table_in a from-clause, as mentioned in docs. Then I replaced table_1 to table_2 in a from-clause. Then I moved on-clause to a where-clause (which, to my knowledge, is exactly the same thing, but why not). And finally I tried your solution with exists. It's all the same, that query hangs time and again. (by 'hangs' I mean it's cancelled with 10s statement_timeout) Commented Aug 24, 2022 at 11:37
  • You don't need an alias for the table if you only "use" each table once.
    – user1822
    Commented Aug 24, 2022 at 11:39
  • it was an act of desperation Commented Aug 24, 2022 at 11:44
  • 1
    @VadimSamokhin You should resort to EXPLAIN long before desperation sets in. As it is, we don't now how it wants to execute the query, nor do we even know what the real query is as you turned it into something not even valid.
    – jjanes
    Commented Aug 24, 2022 at 13:24
  • Yeah, you're absolutely right as always, shame on me. My fault was that I though that if a select-query was fine, then an update-query should be fine either. Thank you for pointing this out. Commented Aug 24, 2022 at 14:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.