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 1jI08B-0007aW-H2 for pgsql-hackers@arkaria.postgresql.org; Sat, 28 Mar 2020 01:19:23 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1jI08A-0001Yc-9j for pgsql-hackers@arkaria.postgresql.org; Sat, 28 Mar 2020 01:19:22 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1jI089-0001YV-Qc for pgsql-hackers@lists.postgresql.org; Sat, 28 Mar 2020 01:19:22 +0000 Received: from mail-wr1-x444.google.com ([2a00:1450:4864:20::444]) by makus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1jI086-0003uX-Od for pgsql-hackers@lists.postgresql.org; Sat, 28 Mar 2020 01:19:20 +0000 Received: by mail-wr1-x444.google.com with SMTP id j17so13926032wru.13 for ; Fri, 27 Mar 2020 18:19:18 -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=VWYzjMxP/gGHTCDzuJxWlEUReqcq8pYbMbuHB3LU4k4=; b=EIw1/V3Ji51GqT8hTXDrq5LlnKI+Q3+7fL9Q9vpMsQl6l8eMPiNyBw3r6kIdQdZ6UQ ownumwnt6vXD2yYopr5df9c2o8hQ/+/kL8qqw60WtwDbGnrtv8BViZCH2ULQjs1P+dlb FkIj3APaq2DswQz2JtGV4DzFCJp4KDRfliqFw6T6yLBdvWV1xqF/V+7bSgKMxoZKjaEd rBpH7/U7O/0WUb2e8t0ok1lD/38Sbk9gPfOC9JbYA04oMudYI4T5l+q8FML70mgmSrsR N85ynMVnQ1Oo+0eqEq1GwLpYLN25xSuM35iGGMetMLT1iT+6SBJd4p0KvCFoGpZsF37v HEBg== 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=VWYzjMxP/gGHTCDzuJxWlEUReqcq8pYbMbuHB3LU4k4=; b=Tt6XseKkhmHxPt8ZTvqxpwRccQru4NAUTDm7qkPkEx9oeZRBDiIKDUlHUZ27jhX/tt enFdpRGSi2wV6CTFEpLoZsYHLNcW3Di/WpAM9shEZckliJMuJVtdlbZbN+yj5RO6qlxK PBiZ9juuF/pr14rgRncq7YzpGnMBGyCbJ6cU3fgrImJHbXqLR/6LAyXfutP6td8XYU4X gabDk1HFaWj9ATnEFb7cwTE4HmFnjeobw/m0tVIQJjV0ZaWVaNPFlO8vfMaBwwznoQv0 fZfxaZNN2PQtwl8hw12zPc3ov0aaAQu1n2DY0J1Lv3+xL8MBEVXKkYWs5ETV+vEMRhyM kZyQ== X-Gm-Message-State: ANhLgQ1rHEdx80PFXURVAcy2B6myJa124ap2kP/qEzwUY7fSLU91eLws 0qK0y2A2Tr48O/mCiHGX82KwcA== X-Google-Smtp-Source: ADFU+vvWjU1ik2j6chYa6GlKalOYp1jJkWI2zdLA4RqvLvVNaL6JrUvStUEEesAm7uvcvj1rgu3uGQ== X-Received: by 2002:adf:fc4c:: with SMTP id e12mr2285752wrs.265.1585358357276; Fri, 27 Mar 2020 18:19:17 -0700 (PDT) Received: from localhost (ip-86-49-253-141.net.upcbroadband.cz. [86.49.253.141]) by smtp.gmail.com with ESMTPSA id y80sm10684569wmc.45.2020.03.27.18.19.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 27 Mar 2020 18:19:16 -0700 (PDT) Date: Sat, 28 Mar 2020 02:19:13 +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: <20200328011913.btjuwwkhieav3aod@development> References: <20200324034438.GA13003@alvherre.pgsql> <20200324230831.5zvjpgayh35bxedp@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 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. >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. >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. >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 > >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. regards -- Tomas Vondra http://www.2ndQuadrant.com PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services