In the meantime you can force it with CTE.

with inv as (
  select id_asset
    , inventory.date
    , quantity
  from inventory
  order by inventory.date
  limit 100
)
select inv.date, asset.name, inv.quantity
from inv
join asset on id_asset = asset.id
order by inv.date, asset.name
;

> On Jun 1, 2018, at 11:12 AM, Steven Winfield 
> <steven.winfi...@cantabcapital.com> wrote:
> 
> It does indeed!
>                                                                            
> QUERY PLAN
> ----------------------------------------------------------------------------------------------------------------------------------------------------------------
> Limit  (cost=398.50..398.50 rows=100 width=32) (actual time=10.359..10.378 
> rows=100 loops=1)
>    Output: inventory.date, asset.name, inventory.quantity
>    ->  Incremental Sort  (cost=398.50..403.27 rows=5006001 width=32) (actual 
> time=10.357..10.365 rows=100 loops=1)
>          Output: inventory.date, asset.name, inventory.quantity
>          Sort Key: inventory.date, asset.name
>          Presorted Key: inventory.date
>          Sort Method: quicksort  Memory: 103kB
>          Sort Groups: 1
>          ->  Nested Loop Left Join  (cost=0.71..1702372.39 rows=5006001 
> width=32) (actual time=0.030..2.523 rows=1002 loops=1)
>                Output: inventory.date, asset.name, inventory.quantity
>                Inner Unique: true
>                ->  Index Scan using inventory_pkey on temp.inventory  
> (cost=0.43..238152.40 rows=5006001 width=12) (actual time=0.016..0.290 
> rows=1002 loops=1)
>                      Output: inventory.date, inventory.id_asset, 
> inventory.quantity
>                ->  Index Scan using asset_pkey on temp.asset  
> (cost=0.28..0.29 rows=1 width=28) (actual time=0.002..0.002 rows=1 loops=1002)
>                      Output: asset.id <http://asset.id/>, asset.name
>                      Index Cond: (asset.id <http://asset.id/> = 
> inventory.id_asset)
>  
> I’m guessing the feature-freeze for v11 means we won’t see this in the that 
> version, though, and the extra GUC it requires means it will be in v12 at the 
> earliest?
>  
> From: James Coleman [mailto:jtc...@gmail.com <mailto:jtc...@gmail.com>] 
> Sent: 01 June 2018 13:50
> To: Christopher Wilson
> Cc: pgsql-hackers@lists.postgresql.org 
> <mailto:pgsql-hackers@lists.postgresql.org>; Steven Winfield
> Subject: Re: FW: Possible optimisation: push down SORT and LIMIT nodes
>  
> The incremental sort patch seems to significantly improve performance for 
> your query: https://commitfest.postgresql.org/17/1124/ 
> <https://commitfest.postgresql.org/17/1124/>
>  
> On Fri, Jun 1, 2018 at 7:46 AM, Christopher Wilson 
> <chris.wil...@cantabcapital.com <mailto:chris.wil...@cantabcapital.com>> 
> wrote:
> Dear Postgres developers,
>  
> I sent this query to the performance list a couple of days ago, but nobody 
> has come up with any suggestions. I was wondering if you’d like to consider 
> it?
>  
> If this is interesting but nobody has time to implement it, then I would 
> potentially be willing to implement and submit it myself, in my own time. I 
> am experienced with C and C++, but I have not modified Postgres before, and I 
> would need significant support (e.g. on IRC) to help me to find my way around 
> the codebase and finish the task in an acceptable amount of time.
>  
> Thanks, Chris.
>  
>  
> 
> From: Christopher Wilson 
> Sent: 30 May 2018 16:47
> To: 'pgsql-performa...@postgresql.org 
> <mailto:pgsql-performa...@postgresql.org>'
> Cc: Steven Winfield (steven.winfi...@cantabcapital.com 
> <mailto:steven.winfi...@cantabcapital.com>)
> Subject: Possible optimisation: push down SORT and LIMIT nodes
>  
> Hi all,
>  
> We have a query which is rather slow (about 10 seconds), and it looks like 
> this:
>  
> select inventory.date, asset.name <http://asset.name/>, inventory.quantity
> from temp.inventory 
> left outer join temp.asset on asset.id <http://asset.id/> = id_asset
> order by inventory.date, asset.name <http://asset.name/>
> limit 100
>  
> The inventory table has the quantity of each asset in the inventory on each 
> date (complete SQL to create and populate the tables with dummy data is 
> below). The query plan looks like this (the non-parallel version is similar):
>  
> <image001.png>
>  
> Or in text form:
>  
> Limit  (cost=217591.77..217603.60 rows=100 width=32) (actual 
> time=9122.235..9122.535 rows=100 loops=1)
>    Buffers: shared hit=6645, temp read=6363 written=6364
>    ->  Gather Merge  (cost=217591.77..790859.62 rows=4844517 width=32) 
> (actual time=9122.232..9122.518 rows=100 loops=1)
>          Workers Planned: 3
>          Workers Launched: 3
>          Buffers: shared hit=6645, temp read=6363 written=6364
>          ->  Sort  (cost=216591.73..220628.83 rows=1614839 width=32) (actual 
> time=8879.909..8880.030 rows=727 loops=4)
>                Sort Key: inventory.date, asset.name <http://asset.name/>
>                Sort Method: external merge  Disk: 50904kB
>                Buffers: shared hit=27365, temp read=25943 written=25947
>                ->  Hash Join  (cost=26.52..50077.94 rows=1614839 width=32) 
> (actual time=0.788..722.095 rows=1251500 loops=4)
>                      Hash Cond: (inventory.id_asset = asset.id 
> <http://asset.id/>)
>                      Buffers: shared hit=27236
>                      ->  Parallel Seq Scan on inventory  (cost=0.00..29678.39 
> rows=1614839 width=12) (actual time=0.025..237.977 rows=1251500 loops=4)
>                            Buffers: shared hit=27060
>                      ->  Hash  (cost=14.01..14.01 rows=1001 width=28) (actual 
> time=0.600..0.600 rows=1001 loops=4)
>                            Buckets: 1024  Batches: 1  Memory Usage: 68kB
>                            Buffers: shared hit=32
>                            ->  Seq Scan on asset  (cost=0.00..14.01 rows=1001 
> width=28) (actual time=0.026..0.279 rows=1001 loops=4)
>                                  Buffers: shared hit=32
> Planning time: 0.276 ms
> Execution time: 9180.144 ms
>  
> I can see why it does this, but I can also imagine a potential optimisation, 
> which would enable it to select far fewer rows from the inventory table.
>  
> As we are joining to the primary key of the asset table, we know that this 
> join will not add extra rows to the output. Every output row comes from a 
> distinct inventory row. Therefore only 100 rows of the inventory table are 
> required. But which ones?
>  
> If we selected exactly 100 rows from inventory, ordered by date, then all of 
> the dates that were complete (every row for that date returned) would be in 
> the output. However, if there is a date which is incomplete (we haven’t 
> emitted all the inventory records for that date), then it’s possible that we 
> would need some records that we haven’t emitted yet. This can only be known 
> after joining to the asset table and sorting this last group by both date and 
> asset name. 
>  
> But we do know that there can only be 0 or 1 incomplete groups: either the 
> last group (by date) is incomplete, if the LIMIT cut it off in mid-group, or 
> its end coincided with the LIMIT boundary and it is complete. As long as we 
> continue selecting rows from this table until we exhaust the prefix of the 
> overall SORT which applies to it (in this case, just the date) then it will 
> be complete, and we will have all the inventory rows that can appear in the 
> output (because no possible values of columns that appear later in the sort 
> order can cause any rows with different dates to appear in the output).
>  
> I’m imagining something like a sort-limit-finish node, which sorts its input 
> and then returns at least the limit number of rows, but keeps returning rows 
> until it exhausts the last sort prefix that it read.
>  
> This node could be created from an ordinary SORT and LIMIT pair:
>  
> SORT + LIMIT -> SORT-LIMIT-FINISH + SORT + LIMIT
>  
> And then pushed down through either a left join, or an inner join on a 
> foreign key, when the right side is unique, and no columns from the right 
> side appear in WHERE conditions, nor anywhere in the sort order except at the 
> end. This sort column suffix would be removed by pushing the node down. The 
> resulting query plan would then look something like:
>  
> Index Scan on inventory
> SORT-LIMIT-FINISH(sort=[inventory.date], limit=100) (pushed down through the 
> join to asset)
> Seq Scan on asset
> Hash Left Join (inventory.id_asset = asset.id <http://asset.id/>)
> Sort (inventory.date, asset.name <http://asset.name/>)
> Limit (100)
>  
> And would emit only about 100-1000 inventory rows from the index scan.
>  
> Does this sound correct, reasonable and potentially interesting to Postgres 
> developers?
>  
> SQL to reproduce:
>  
> create schema temp;
> create table temp.asset (
>         id serial primary key,
>         name text
> );
> insert into temp.asset (name) select 'Thing ' || random()::text as name from 
> generate_series(0, 1000) as s;
> create table temp.inventory (
>         date date,
>         id_asset int,
>         quantity int,
>         primary key (date, id_asset),
>         CONSTRAINT id_asset_fk FOREIGN KEY (id_asset) REFERENCES temp.asset 
> (id) MATCH SIMPLE
> );
> insert into temp.inventory (date, id_asset, quantity)
> select current_date - days, asset.id <http://asset.id/>, random() from 
> temp.asset, generate_series(0, 5000) as days;
>  
> Thanks, Chris.
>  
> This email is confidential. If you are not the intended recipient, please 
> advise us immediately and delete this message. The registered name of Cantab- 
> part of GAM Systematic is Cantab Capital Partners LLP. See - 
> http://www.gam.com/en/Legal/Email+disclosures+EU 
> <http://www.gam.com/en/Legal/Email+disclosures+EU> for further information on 
> confidentiality, the risks of non-secure electronic communication, and 
> certain disclosures which we are required to make in accordance with 
> applicable legislation and regulations. If you cannot access this link, 
> please notify us by reply message and we will send the contents to you.
> 
> GAM Holding AG and its subsidiaries (Cantab – GAM Systematic) will collect 
> and use information about you in the course of your interactions with us. 
> Full details about the data types we collect and what we use this for and 
> your related rights is set out in our online privacy policy at 
> https://www.gam.com/en/legal/privacy-policy 
> <https://www.gam.com/en/legal/privacy-policy>. Please familiarise yourself 
> with this policy and check it from time to time for updates as it supplements 
> this notice

Reply via email to