Thanks for the replies Jeff, Tom and Merlin.

>> Pages that SELECT multiple rows with OFFSET and LIMIT conditions struggle to 
>> top 1.3k req/s
> 
> Is that tested at the OFFSET and LIMIT of 0 and 15, as shown in the
> explain plan?


Yes — 0 (OFFSET) and 16 (LIMIT), or 15 and 31 (i.e. “second page” of results). 
There’s no difference on that front. For context, OFFSET is a multiple of 15 
(i.e. 15 results per page) and LIMIT is always 15 + 1 in an attempt to fetch 
one more result, get the len of the returned slice and then return paginate 
true + slice the last result off if there’s more than 15.

> 
> 
>> The query in question is: http://explain.depesz.com/s/7g8 and the table 
>> schema is as below:
> 
> The reported runtime of 0.078 ms should be able to sustain nearly 10
> times the reported rate of 1.3k/s, so the bottleneck would seem to be
> elsewhere.
> 
> Perhaps the bottleneck is formatting the result set in postgres to be
> sent over the wire, then sending it over the wire, then parsing it in
> the Go connection library to hand back to the Go user code, and then
> the Go user code doing something meaningful with it.
> 
> What happens if you get rid of the offset and the order by, and just
> use limit?  I bet it doesn't change the speed much (because that is
> not where the bottleneck is).
> 
> You seem to be selecting an awful lot of wide columns.  Do you really
> need to see all of them?

- Testing SELECT * FROM … with just LIMIT 15 and no offset yields 1299 
request/s at the front end of the application.
- Testing SELECT id, title, company, location, commute, term, expiry_date (a 
subset of fields) with LIMIT 15 and no OFFSET yields 1800 request/s at the 
front end.

There’s definitely an increase to be realised there (I’d say by just tossing 
the rendered HTML field). 

Based on your comments about the Go side of things, I ran a quick test by 
cutting the table down to 6 records from the 39 in the test DB in all previous 
tests. This skips the pagination logic (below) and yields 3068 req/s on the 
front-end. 

        // Determine if we have more than one page of results.
        // If so, trim the extra result off and set pagination = true
        if len(listings) > opts.PerPage {
                paginate = true
                listings = listings[:opts.PerPage]
        }

So there certainly appears to be a bottleneck on the Go side as well (outside 
of even the DB driver), probably from the garbage generated from slicing the 
slice, although I’d be keen to know if there’s a better way to approach 
returning a paginated list of results.

>>> Well, you can also do client side pagination using the row-wise
>>> comparison feature, implemented by you :-).  Cursors can be the best
>>> approach, but it's nice to know the client side approach if you're
>>> really stateless and/or want to be able to pick up external changes
>>> during the browse.


What would be a better approach here? The cursor approach isn’t ideal in my 
case (although I could make it work), but what other options are there that are 
stateless?


>> 
>> Some pgbench results from this machine as well:
>> 
>> $ pgbench -c 128 -C -j 4 -T 15 -M extended -S
> 
> This is just benchmarking how fast you can make and break connections
> to the database.
> 
> Because your app is using an embedded connection pooler, this
> benchmark isn't very relevant to your situation.


Noted — thanks.


On 13 Jun 2014, at 4:46 AM, Jeff Janes <jeff.ja...@gmail.com> wrote:

> <snip>

Reply via email to