Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1horEk-0006tl-Hf for pgsql-hackers@arkaria.postgresql.org; Sat, 20 Jul 2019 15:25:26 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1horEh-000454-UT for pgsql-hackers@arkaria.postgresql.org; Sat, 20 Jul 2019 15:25:23 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1horEh-000415-L9 for pgsql-hackers@lists.postgresql.org; Sat, 20 Jul 2019 15:25:23 +0000 Received: from mail-wm1-x344.google.com ([2a00:1450:4864:20::344]) by magus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1horEZ-0000Sz-T6 for pgsql-hackers@lists.postgresql.org; Sat, 20 Jul 2019 15:25:22 +0000 Received: by mail-wm1-x344.google.com with SMTP id u25so21159339wmc.4 for ; Sat, 20 Jul 2019 08:25:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=2ndquadrant-com.20150623.gappssmtp.com; s=20150623; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=SPZAaOI9SOv59X+aPcxQOriUzifkDqfMoNE1AqPziuA=; b=GkqvT4629exYn7mup5tg9NBYIS1Icf1WHOy1cNCuNTTvtr9UDESnTq2bedCxx+wHNN DfEnlIDxQRA6zHc6wNuwwKaFbpl2HD/KKqr5KEGBjyy73bBuC0HAC4h7pPj4G+QabN4o be+XQ6pxV09sCtTp+vfT4j5wgyWvmAS6lTPLQS+bdJV1NqFJyOd7/tWovvZZOv+sU4Bg nJDEneXnOreQV6gQJq/d2tMA+Qafl3ZrUU/jBT4dnOQKym7MPE/TzP32TZVckat3m1Ye wcp4kXI9pYDZ/YLErqFi35Xb8+uoqWR7pnHe+gI307JqwTuvyT/l1Alew+jlprjToZML y0+w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=SPZAaOI9SOv59X+aPcxQOriUzifkDqfMoNE1AqPziuA=; b=WTsn5bQ53uikp/C/9P5a7x6EKOzMr34FxyAmd/UgAg23fN2zTiua0G8id1+RizaLGe duN0r+cGLIKwJm8O155hTZBmdbME1kc8kCtbguFkbc/6P2/grPKSEF32xq32CETHERjc zQ7HJ6JHJgegMGi9japlyt2lAo3v+DyNYJJ0xQfFgxPlozUT5MXSQ2sBK961fTaJaA/4 EiXbw8IKJzC2QmWt+3f67PkjUoYxOu1DZGyhhAbWR7mzTGM6AcgHmvMBvWvcji/RWLfl 9Z7LBfJoW+N0L25C1cj6SALST+HbOlojckm77mQ5wApBI2NFk2dS+3VRNdSfJtV5G5Fu ZLzQ== X-Gm-Message-State: APjAAAV+p2b1n85JnFPLbb5SKHeScowlaShomm0vf8eOgviV3Lu12TQS aXGVGF7ndTmkTclQS1hxKcvoIw== X-Google-Smtp-Source: APXvYqwyCTsKH9jvM5NaZY8iRz3c4N1vbZ9g6LEKybrvSovT4TEQRrr/AFjTxNpdk3vlSZeuYSsRDA== X-Received: by 2002:a7b:c04f:: with SMTP id u15mr53030674wmc.106.1563636314686; Sat, 20 Jul 2019 08:25:14 -0700 (PDT) Received: from localhost (ip-86-49-253-160.net.upcbroadband.cz. [86.49.253.160]) by smtp.gmail.com with ESMTPSA id b5sm28069806wru.69.2019.07.20.08.25.13 (version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256); Sat, 20 Jul 2019 08:25:13 -0700 (PDT) Date: Sat, 20 Jul 2019 17:25:12 +0200 From: Tomas Vondra To: James Coleman Cc: Peter Geoghegan , Simon Riggs , Rafia Sabih , Shaun Thomas , Dmitry Dolgov <9erthalion6@gmail.com>, Alexander Korotkov , Tom Lane , PostgreSQL Developers Subject: Re: [PATCH] Incremental sort (was: PoC: Partial sort) Message-ID: <20190720152512.jpdi2g3notbjcxsd@development> References: <20190707210205.4lxkbq6tpjcj2hlk@development> <20190708135933.oco3gyloeacdj7yy@development> <20190708145853.x2doaqcyj3enol2e@development> <20190709013703.3mbdhsv2gyxtjc42@development> <20190720132244.3vgg2uynfpxh3me5@development> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Disposition: inline In-Reply-To: User-Agent: NeoMutt/20180716-1444-295967 List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk On Sat, Jul 20, 2019 at 10:33:02AM -0400, James Coleman wrote: >On Sat, Jul 20, 2019 at 9:22 AM Tomas Vondra > wrote: >> >> On Fri, Jul 19, 2019 at 04:59:21PM -0400, James Coleman wrote: >> >On Mon, Jul 8, 2019 at 9:37 PM Tomas Vondra >> > wrote: >> >> Now, consider this example: >> >> >> >> create table t (a int, b int, c int); >> >> insert into t select mod(i,100),mod(i,100),i from generate_series(1,10000000) s(i); >> >> create index on t (a); >> >> analyze t; >> >> explain select a,b,sum(c) from t group by 1,2 order by 1,2,3 limit 1; >> >> >> >> With 0001+0002+0003 pathes, I get a plan like this: >> >> >> >> QUERY PLAN >> >> -------------------------------------------------------------------------------------------------------------------- >> >> Limit (cost=10375.39..10594.72 rows=1 width=16) >> >> -> Incremental Sort (cost=10375.39..2203675.71 rows=10000 width=16) >> >> Sort Key: a, b, (sum(c)) >> >> Presorted Key: a, b >> >> -> GroupAggregate (cost=10156.07..2203225.71 rows=10000 width=16) >> >> Group Key: a, b >> >> -> Gather Merge (cost=10156.07..2128124.39 rows=10000175 width=12) >> >> Workers Planned: 2 >> >> -> Incremental Sort (cost=9156.04..972856.05 rows=4166740 width=12) >> >> Sort Key: a, b >> >> Presorted Key: a >> >> -> Parallel Index Scan using t_a_idx on t (cost=0.43..417690.30 rows=4166740 width=12) >> >> (12 rows) >> >> >> >> >> >> and with 0004, I get this: >> >> >> >> QUERY PLAN >> >> ------------------------------------------------------------------------------------------------------ >> >> Limit (cost=20443.84..20665.32 rows=1 width=16) >> >> -> Incremental Sort (cost=20443.84..2235250.05 rows=10000 width=16) >> >> Sort Key: a, b, (sum(c)) >> >> Presorted Key: a, b >> >> -> GroupAggregate (cost=20222.37..2234800.05 rows=10000 width=16) >> >> Group Key: a, b >> >> -> Incremental Sort (cost=20222.37..2159698.74 rows=10000175 width=12) >> >> Sort Key: a, b >> >> Presorted Key: a >> >> -> Index Scan using t_a_idx on t (cost=0.43..476024.65 rows=10000175 width=12) >> >> (10 rows) >> >> >> >> Notice that cost of the second plan is almost double the first one. That >> >> means 0004 does not even generate the first plan, i.e. there are cases >> >> where we don't try to add the explicit sort before passing the path to >> >> generate_gather_paths(). >> >> >> >> And I think I know why is that - while gather_grouping_paths() tries to >> >> add explicit sort below the gather merge, there are other places that >> >> call generate_gather_paths() that don't do that. In this case it's >> >> probably apply_scanjoin_target_to_paths() which simply builds >> >> >> >> parallel (seq|index) scan + gather merge >> >> >> >> and that's it. The problem is likely the same - the code does not know >> >> which pathkeys are "interesting" at that point. We probably need to >> >> teach planner to do this. >> > >> >I've been working on figuring out sample queries for each of the >> >places we're looking at adding create_increment_sort() (starting with >> >the cases enabled by gather-merge nodes). The >> >generate_useful_gather_paths() call in >> >apply_scanjoin_target_to_paths() is required to generate the above >> >preferred plan. > >As I continue this, I've added a couple of test cases (notably for >generate_useful_gather_paths() in both standard_join_search() and >apply_scanjoin_target_to_paths()). Those, plus the current WIP state >of my hacking on your patch adding generate_useful_gather_paths() is >attached as 0001-parallel-and-more-paths.patch. > >My current line of investigation is whether we need to do anything in >the parallel portion of create_ordered_paths(). I noticed that the >first-pass patch adding generate_useful_gather_paths() modified that >section but wasn't actually adding any new gather-merge paths (just >bare incremental sort paths). That seems pretty clearly just a >prototype miss, so I modified the prototype to build gather-merge >paths instead (as a side note that change seems to fix an oddity I was >seeing where plans would include a parallel index scan node even >though they weren't parallel plans). While the resulting plan for >something like: > Yes, that seems to be a bug. The block above it clealy has a gather merge nodes, so this one should too. >explain analyze select * from t where t.a in (1,2,3,4,5,6) order by >t.a, t.b limit 50; > >changes cost (to be cheaper) ever so slightly with the gather-merge >addition to create_ordered_paths(), the plan itself is otherwise >identical (including row estimates): > >Limit > -> Gather Merge > -> Incremental Sort > -> Parallel Index Scan > >(Note: I'm forcing parallel plans here with: set >max_parallel_workers_per_gather=4; set min_parallel_table_scan_size=0; >set parallel_tuple_cost=0; set parallel_setup_cost=0; set >min_parallel_index_scan_size=0;) > >I can't seem to come up with a case where adding these gather-merge >paths in create_ordered_paths() isn't entirely duplicative of paths >already created by generate_useful_gather_paths() as called from >apply_scanjoin_target_to_paths() -- which I _think_ makes sense given >that both apply_scanjoin_target_to_paths() and create_ordered_paths() >are called by grouping_planner(). > >Can you think of a case I'm missing here that would make it valuable >to generate new parallel plans in create_ordered_paths()? > Good question. Not sure. I think such path would need to do something on a relation that is neither a join nor a scan - in which case the path should not be created by apply_scanjoin_target_to_paths(). So for example a query like this: SELECT a, b, sum(expensive_function(c)) FROM t GROUP BY a,b ORDER BY a,sum(...) LIMIT 10; should be able to produce a plan like this: -> Limit -> Gather Merge -> Incremental Sort (pathkeys: a, sum) -> Group Aggregate a, b, sum(expensive_function(c)) -> Index Scan (pathkeys: a, b) or something like that, maybe. I haven't tried this, though. The other question is whether such queries are useful in practice ... >> ... >> >> I think this may be a thinko, as this plan demonstrates - but I'm not >> sure about it. I wonder if this might be penalizing some other types of >> plans (essentially anything with limit + gather). >> >> Attached is a WIP patch fixing this by considering both startup and >> total cost (by calling compare_path_costs_fuzzily). > >It seems to me that this is likely a bug, and not just a changed >needed for this. Do you think it's better addressed in a separate >thread? Or retain it as part of this patch for now (and possibly break >it out later)? On the other hand, it's entirely possible that someone >more familiar with parallel plan limitations could explain why the >above comment holds true. That makes me lean towards asking in a new >thread. > Maybe. I think creating a separate thread would be useful, provided we manage to demonstrate the issue without an incremental sort. >I've also attached a new base patch (incremental-sort-30.patch) which >includes some of the other obvious fixes (costing, etc.) that you'd >previously proposed. > Thanks! -- Tomas Vondra http://www.2ndQuadrant.com PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services