pg.ddx.io  pgsql-performance@postgresql.org mailing list archive  
help / color / mirror / Atom feed
From: Gunther Schadow <gunther@pragmaticdata.com>
To: pgsql-performance@lists.postgresql.org
Subject: Re: Massive parallel queue table causes index deterioration, but REINDEX fails with deadlocks.
Date: Sun, 24 Feb 2019 22:06:02 -0500
Message-ID: <9600aa3c-25a0-e057-e693-216fba4145b6@pragmaticdata.com> (raw)
In-Reply-To: <CAMkU=1z03uq-GHQ+Dgv7ksEVyTA6QzAbSkxVmj3GK-WGK2W=gw@mail.gmail.com>
References: <33bae6e3-1c5a-77f0-ee99-408fbf0fbb83@gusw.net>
	<CAKJS1f_kxF=3K=D8MXa2NwdycwKJsNqVXNXyeDWv3t9f3p6J2A@mail.gmail.com>
	<c044fc83-4816-e846-e78c-b4d6961efb6f@gusw.net>
	<CAMkU=1z03uq-GHQ+Dgv7ksEVyTA6QzAbSkxVmj3GK-WGK2W=gw@mail.gmail.com>

Wow, yes, partition instead of index, that is interesting. Thanks Corey 
and Justin.

The index isn't required at all if all my pending jobs are in a 
partition of only pending jobs. In that case the plan can just be a 
sequential scan.

And Jeff James, sorry, I failed to show the LIMIT 1 clause on my dequeue 
query. That was an omission. My query is actually somewhat more complex 
and I just translated it down to the essentials but forgot the LIMIT 1 
clause.

SELECT seqNo, action
   FROM Queue
  WHERE pending
    AND/... other criteria .../
  LIMIT 1
  FOR UPDATE SKIP LOCKED;

And sorry I didn't capture the stats for vacuum verbose. And they would 
be confusing because there are other things involved.

Anyway, I think the partitioned table is the right and brilliant 
solution, because an index really isn't required. The actual pending 
partition will always remain quite small, and being a queue, it doesn't 
even matter how big it might grow, as long as new rows are inserted at 
the end and not in the middle of the data file and still there be some 
way of fast skip over the part of the dead rows at the beginning that 
have already been processed and moved away.

Good thing is, I don't worry about maintenance window.  I have the 
leisure to simply tear down my design now and make a better design. 
What's 2 million transactions if I can re-process them at a rate of 
80/s? 7 hours max. I am still in development. So, no need to worry about 
migration / transition acrobatics. So if I take Corey's steps and 
envision the final result, not worrying about the transition steps, then 
I understand this:

1. Create the Queue table partitioned on the pending column, this 
creates the partition with the pending jobs (on which I set the 
fillfactor kind of low, maybe 50) and the default partition with all the 
rest. Of course that allows people with a constant transaction volume to 
also partition on jobId or completionTime and move chunks out to cold 
archive storage. But that's beside the current point.

2. Add all needed indexes on the partitioned table, except the main 
partial index that I used before and that required all that reindexing 
maintenance. Actually I won't need any other indexes really, why invite 
another similar problem again.

That's really simple.

One question I have though: I imagine our pending partition heap file to 
now be essentially sequentially organized as a queue. New jobs are 
appended at the end, old jobs are at the beginning. As pending jobs 
become completed (pending = false) these initial rows will be marked as 
dead. So, while the number of live rows will remain small in that 
pending partition, sequential scans will have to skip over the dead rows 
in the beginning.

Does PostgreSQL structure its files such that skipping over dead rows is 
fast? Or do the dead rows have to be read and discarded during a table 
scan?

Of course vacuum eliminates dead rows, but unless I do vacuum full, it 
will not re-pack the live rows, and that requires an exclusive table 
lock. So, what is the benefit of vacuuming that pending partition? What 
I _/don't/_ want is insertion of new jobs to go into open slots at the 
beginning of the file. I want them to be appended (in Oracle there is an 
INSERT /*+APPEND*/ hint for that. How does that work in PostgreSQL?

Ultimately that partition will amass too many dead rows, then what do I 
do? I don't think that the OS has a way to truncate files physically 
from the head, does it? I guess it could set the file pointer from the 
first block to a later block. But I don't know of an IOCTL/FCNTL command 
for that. On some OS there is a way of making blocks sparse again, is 
that how PostgreSQL might do it? Just knock out blocks as sparse from 
the front of the file?

If not, the next thing I can think of is to partition the table further 
by time, may be alternating even and odd days, such that on any given 
day one of the two pending partitions are quiet? Is that how it's done?

regards,
-Gunther

view thread (21+ messages)  latest in thread

Message-ID: <9600aa3c-25a0-e057-e693-216fba4145b6@pragmaticdata.com>
Permalink:  ../9600aa3c-25a0-e057-e693-216fba4145b6@pragmaticdata.com/
Also on:    postgresql.org/message-id/9600aa3c-25a0-e057-e693-216fba4145b6@pragmaticdata.com

 · 

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: pgsql-performance@postgresql.org
  Cc: gunther@pragmaticdata.com, pgsql-performance@lists.postgresql.org
  Subject: Re: Massive parallel queue table causes index deterioration, but REINDEX fails with deadlocks.
  In-Reply-To: <9600aa3c-25a0-e057-e693-216fba4145b6@pragmaticdata.com>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox