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.92) (envelope-from ) id 1jI1gH-0002qg-0v for pgsql-hackers@arkaria.postgresql.org; Sat, 28 Mar 2020 02:58:41 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1jI1gF-0002Qt-1T for pgsql-hackers@arkaria.postgresql.org; Sat, 28 Mar 2020 02:58:39 +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 1jI1gE-0002MG-K6 for pgsql-hackers@lists.postgresql.org; Sat, 28 Mar 2020 02:58:38 +0000 Received: from mail-wm1-x342.google.com ([2a00:1450:4864:20::342]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1jI1gA-0002lX-C0 for pgsql-hackers@lists.postgresql.org; Sat, 28 Mar 2020 02:58:37 +0000 Received: by mail-wm1-x342.google.com with SMTP id d1so14854853wmb.2 for ; Fri, 27 Mar 2020 19:58:33 -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; bh=dz+38a/Z7+5RhbNVpvVDc1FES2jHABiN8qgG7NF4qTM=; b=hrH0Uq2jtAl59ow+2QvkQUiENYBJ61bXG3i5qWNChHc6eD7xKVMcFdQ+uaC+gyKM8D s4Of5mRbl67cHvcHhSKpLzJEvvZDpXv0ijHk93+eWqbaB/qZaWSZtCHBIouun9DECJTQ mFlIZa2S9DTruDRPZ26JH51ATqG+ixbKYvaKccDxdJN58ImhcC3GUjbsQu36OQuX7/1s SwU9bSkyqzF2JnlD9xss+FmElMEhY9BNggX8rFSlFypufLLOLMLZDnJ/hFshZ5t6peqV pnty5Kn4dTBNuH3jjH+/iQVqrOI2HD/XenXLKRUp4cJNfbmnTA7YvSqMCrIGobAMkTpf NOBg== 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; bh=dz+38a/Z7+5RhbNVpvVDc1FES2jHABiN8qgG7NF4qTM=; b=iAPQZ3yYALNNU8cbhZ1XF6p4TBAIApufsqDejjTfdwJ6SXDafGP01ZOBYN1+JrVzjn 7j1XT/2NDsaSZlcZlkZ02DC9hIo2WrCiYoBLrpqqUW9tOSp1aqSy6PZegiKRhdz1ESP4 WsxVJJgkCdJ1XgwwvTgb0WNYte9O3vjGx949+AVsTTcTG711ibtQKwudppDBfkqDY/zx ZXbbFyS3gaAUBSBf0Dj/mm40zHmY+/+QKolYdVfwlHrXZ1ltYJ12z1xNqUqlfPn0YR6O 3zntFZj2GQoWI+1QxC0eh3b/EAXN3CTBthG6T3vyJ3Xd+FfcuEA64PjO/SYKJcZcpMMA FGEQ== X-Gm-Message-State: ANhLgQ26uQMS3ACeDj9qW+K4UcxN9y4oD79rMPouse5htObUFZ80N3eV vT4JeKcGKtqm5rS2HqwdOk+QUQ== X-Google-Smtp-Source: ADFU+vtaU1+QOAqlcWu15q6OIC0BjAXDqX7yTLMSauCoYBuij/MB4hbAm7QQl+RDvYK0PHxIP66Skw== X-Received: by 2002:a1c:6885:: with SMTP id d127mr1706764wmc.33.1585364312860; Fri, 27 Mar 2020 19:58:32 -0700 (PDT) Received: from localhost (ip-86-49-253-141.net.upcbroadband.cz. [86.49.253.141]) by smtp.gmail.com with ESMTPSA id y189sm10884481wmb.26.2020.03.27.19.58.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 27 Mar 2020 19:58:31 -0700 (PDT) Date: Sat, 28 Mar 2020 03:58:30 +0100 From: Tomas Vondra To: James Coleman Cc: Alvaro Herrera , Michael Paquier , Rafia Sabih , Peter Geoghegan , Simon Riggs , Shaun Thomas , Dmitry Dolgov <9erthalion6@gmail.com>, Alexander Korotkov , Tom Lane , PostgreSQL Developers , Andreas Karlsson Subject: Re: [PATCH] Incremental sort (was: PoC: Partial sort) Message-ID: <20200328025830.6v6ogkseohakc32q@development> References: <20200324034438.GA13003@alvherre.pgsql> <20200324230831.5zvjpgayh35bxedp@development> <20200328011913.btjuwwkhieav3aod@development> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Disposition: inline In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk On Fri, Mar 27, 2020 at 09:36:55PM -0400, James Coleman wrote: >On Fri, Mar 27, 2020 at 9:19 PM Tomas Vondra > wrote: >> >> On Fri, Mar 27, 2020 at 12:51:34PM -0400, James Coleman wrote: >> >In a previous email I'd summarized remaining TODOs I'd found. Here's >> >an updated listed with several resolved. >> > >> >Resolved: >> > >> >2. Not marked in the patch, but in nodeIncrementalSort.c >> >ExecIncrementalSort() I wonder if perhaps we should move the algorithm >> >discussion comments up to the file header comment. On the other hand, >> >I suppose it could be valuable to leave the the file header comment >> >more high level about the mathematical properties of incremental sort >> >rather than discussing the details of the hybrid mode. >> > >> >I've decided to do this, and the attached patch series includes the change. >> > >> >> It's a bit tough to find the right balance what to put into the header >> comment and what should go to function comments, but this seems mostly >> reasonable. I wouldn't use the double-tab indentation and the copyright >> notices should stay at the top. > >Fixed. I also re-ran pg_indent on the the nodeIncrementalSort.c file. > >> >3. nodeIncrementalSort.c ExecIncrementalSort() in the main for loop: >> > * TODO: do we need to check for interrupts inside these loops or >> > * will the outer node handle that? >> > >> >It seems like what we have is sufficient, given that the nodes (and >> >sort) we rely on have their own calls. The one place where someone >> >might make an argument otherwise would be in the mode transition >> >function where we copy tuples from the full sort state to the >> >presorted sort state. If this is a problem, let me know, and I'll >> >change it, but I'm proceeding under the assumption for now that it's >> >not. >> > >> >> I think what we have now is sufficient. >> >> >4. nodeIncrementalSort.c ExecReScanIncrementalSort: This whole chunk >> >is suspect. I've mentioned previously I don't have a great mental >> >model of how rescan works and its invariants (IIRC someone said it was >> >about moving around a result set in a cursor). Regardless I'm pretty >> >sure this code just doesn't work correctly. Additionally the sort_Done >> >variable is poorly named; it probably would make more sense to call it >> >something like "scanHasBegun". I'm waiting to change it though until >> >cleaning up this code more holistically. >> > >> >Fixed, as described in previous email. >> > >> >6. regress/expected/incremental_sort.out: >> >-- TODO if an analyze happens here the plans might change; should we >> >-- solve by inserting extra rows or by adding a GUC that would somehow >> >-- forcing the time of plan we expect. >> > >> >I've decided this doesn't seem to be a real issue, so, comment removed. >> > >> >> OK >> >> >7. Not listed as a comment in the patch, but I need to modify the >> >testing for analyze output to parse out the memory/disk stats to the >> >tests are stable. >> > >> >Included in the attached patch series. I use plpgsql to munge out the >> >space kB numbers. I also discovered two bugs in the JSON output along >> >the way and fixed those (memory and disk need to be output separate; >> >disk was using the wrong "space type" enum). Finally I also use >> >plpgsql to check a few invariants (for now just that max space is >> >greater than or equal to the average. >> > >> >> OK >> >> >8. optimizer/path/allpaths.c get_useful_pathkeys_for_relation: >> >* XXX At the moment this can only ever return a list with a single element, >> >* because it looks at query_pathkeys only. So we might return the pathkeys >> >* directly, but it seems plausible we'll want to consider other orderings >> >* in the future. >> > >> >I think we just leave this in as a comment. >> > >> >> Fine with me. >> >> As a side note here, I'm wondering if this (determining useful pathkeys) >> can be made a bit smarter by looking both at query_pathkeys and pathkeys >> useful for merging, similarly to what truncate_useless_pathkeys() does. >> But that can be seen as an improvement of what we do now. > >Unless your comment below about looking at truncate_useless_pathkeys >is implying you're considering aiming to get this in now, I wonder if >we should just expand the comment to reference pathkeys useful for >merging as a possible future extension. > Maybe. I've been thinking about how to generate those path keys, but it's a bit tricky, because pathkeys_useful_for_merging() - the thing that backs truncate_useless_pathkeys() actually gets pathkeys and merely verifies if those are useful for merging. But this code needs to do the opposite - generate those pathkeys. But let's say we know we have a join on columns (a,b,c). For each of those PathKey values we know it's useful for merging, but should we generate pathkeys (a,b,c), (b,c,a), ... or any other permutation? I suppose we can look at pathkeys for existing paths of the relation to prune the possibilities a bit, but what then? BTW I wonder if we actually need the ec_has_volatile check in get_useful_pathkeys_for_relation. The comment says we can't but is it really true? pathkeys_useful_for_ordering doesn't do any such checks, so I'd bet this is merely an unnecessary copy-paste from postgres_fdw. Opinions? >> >9. optimizer/path/allpaths.c get_useful_pathkeys_for_relation: >> >* Considering query_pathkeys is always worth it, because it might let us >> >* avoid a local sort. >> > >> >That originally was a copy from the fdw code, but since the two >> >functions have diverged (Is that concerning? I could be confusing, but >> >isn't a compilation problem) I didn't move the function. >> > >> >> I think it's OK the two functions diverged, it's simply because the FDW >> one needs to check other things too. But I might rework this once I look >> closer at truncate_useless_pathkeys. > >Agreed, for now at least. It's tempting to think they should always be >shared, but I'm not convinced (without a lot more digging) that this >represents structural rather than incidental duplication. > The more I look at pathkeys_useful_for_ordering() the more I think the get_useful_pathkeys_for_relation() function should look more like it than the postgres_fdw one ... >> >I did notice though that find_em_expr_for_rel() is wholesale copied >> >(and unchanged) from the fdw code, so I moved it to equivclass.c so >> >both places can share it. >> > >> >> +1 >> ... which would also get rid of find_em_expr_for_rel(). >> > >> >Still remaining: >> > >> >1. src/backend/optimizer/util/pathnode.c add_partial_path() >> >* XXX Perhaps we could do this only when incremental sort is enabled, >> >* and use the simpler version (comparing just total cost) otherwise? >> > >> >I don't have a strong opinion here. It doesn't seem like a significant >> >difference in terms of cost? >> > >> >5. planner.c create_ordered_paths: >> >* XXX This only looks at sort_pathkeys. I wonder if it needs to look at the >> >* other pathkeys (grouping, ...) like generate_useful_gather_paths. >> > >> >10. optimizer/path/allpaths.c generate_useful_gather_paths: >> >* XXX I wonder if we need to consider adding a projection here, as >> >* create_ordered_paths does. >> > >> >11. In the same function as the above: >> >* XXX Can't we skip this (maybe only for the cheapest partial path) >> >* when the path is already sorted? Then it's likely duplicate with >> >* the path created by generate_gather_paths. >> > >> >12. In the same function as the above: >> >* XXX This is not redundant with the gather merge path created in >> >* generate_gather_paths, because that merely preserves ordering of >> >* the cheapest partial path, while here we add an explicit sort to >> >* get match the useful ordering. >> > >> >13. planner.c create_ordered_paths: >> >* XXX This is probably duplicate with the paths we already generate >> >* in generate_useful_gather_paths in apply_scanjoin_target_to_paths. >> > >> >Tomas, any chance you could take a look at the above XXX/questions? I >> >believe all of them that remain relate to the planner patches. >> > >> >> Yes, I'll take a look over the weekend. > >Awesome, thanks. > >I collapsed things down including the changes referenced in this >email, since they were all comment formatting changes. > Thanks. -- Tomas Vondra http://www.2ndQuadrant.com PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services