Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1jJ5Tx-0005tY-Iy for pgsql-hackers@arkaria.postgresql.org; Tue, 31 Mar 2020 01:14:21 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1jJ5Tu-0006qM-Ss for pgsql-hackers@arkaria.postgresql.org; Tue, 31 Mar 2020 01:14:18 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1jJ5Tu-0006pd-EQ for pgsql-hackers@lists.postgresql.org; Tue, 31 Mar 2020 01:14:18 +0000 Received: from mail-wm1-x344.google.com ([2a00:1450:4864:20::344]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1jJ5Tq-0004dP-R3 for pgsql-hackers@lists.postgresql.org; Tue, 31 Mar 2020 01:14:17 +0000 Received: by mail-wm1-x344.google.com with SMTP id r16so749996wmg.5 for ; Mon, 30 Mar 2020 18:14:14 -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=t4Ko2A96FNnBzVUfN7HWtZ7Rtk5wTuumPSu51JhEzZ4=; b=m6ynCl/Xo6QixwuGk78tHZS4Gc9Ovy6UAV3cb+60dA6FKESEXXR9KDBFH252PUN575 ky3gEuAL3+KYvSacHFzFfqiLV1nI47RjI1zNNsS3EC2Qua2YoJcAGmWqr54edKT2p0rY pAneL4xurLnfr12GpaTPXpCB7aWFpT4E0tORRaLtGgYYE47iQlWF+dYVVPRTecI4Q3wq xTavWkMEdICNOMuhrRwz+oZYgQu3C/OI+e2AAmp9TeB66g685yZw2WhI+42Q1qBJ4iSG a/76fKol4PT9+we+suXDQb/PIwyiVD4MFg0SAVzB9kbT1oyuRBzgLmTVXg0ZTDs04p56 uU4A== 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=t4Ko2A96FNnBzVUfN7HWtZ7Rtk5wTuumPSu51JhEzZ4=; b=TgIZ//KiTLj4CkCrbdo2ammZXjXY3g09YJU6Rto42jmKt/qwBfPwnUcPqOymyB1yVx F5jAnZLS7VG27qsIyQ5QnMB5ouPfhwoiePJ2sIFx36pKF0t1ehqG4Hg5wpD3jJWTj8XA 0wYQsxrbzfYuEPVgeoRnhXzt9rz0M6GP8c9PH/9cYF/C8PbY3vLC8PYk5X0wVoWtkH15 XjDdAoP716bAJJvv4Rv51IXoci9SXKhveRL06Ebe8ikgFSUuCqvJK2ccPKPkZge0G3fE 8/Ea1/3/Q+07ZG3kwxsC3CwjWX80uk4OniP5bnBw/A6npEq0u4Ky7AvuXdERp7Ueh5MD XL4g== X-Gm-Message-State: ANhLgQ3b8BpJAiF1MD8lYdV8W6pfc5DudhF2xlYuLSTOX+sTRvRkGk8W vsBnzTyEZRH5MyGoDMwptmBByw== X-Google-Smtp-Source: ADFU+vvv7HxEjE/Oy0YLbiuF9EOpOiQafyMlunq4MTq64nQU1pcgRiuiK7Paw4AV3TMJyBy3uV1lAA== X-Received: by 2002:a1c:5506:: with SMTP id j6mr778326wmb.127.1585617253680; Mon, 30 Mar 2020 18:14:13 -0700 (PDT) Received: from localhost (ip-86-49-253-141.net.upcbroadband.cz. [86.49.253.141]) by smtp.gmail.com with ESMTPSA id k83sm1801952wma.3.2020.03.30.18.14.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 30 Mar 2020 18:14:12 -0700 (PDT) Date: Tue, 31 Mar 2020 03:14:07 +0200 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: <20200331011407.vwz3ektatgqyi6vy@development> References: <20200328213050.byyeuozylnxv2bhf@development> <20200328225922.ljnw54bfg44vi6ib@development> <20200329031437.yvhogo25wdijwpqd@development> <20200330014442.chqnwfmelm3ejsgr@development> <20200330122426.wjdfpqiatv4ybui7@development> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="gfn46hvoqmkpjtbs" Content-Disposition: inline In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk --gfn46hvoqmkpjtbs Content-Type: text/plain; charset=us-ascii; format=flowed Content-Disposition: inline On Mon, Mar 30, 2020 at 06:53:47PM -0400, James Coleman wrote: >On Mon, Mar 30, 2020 at 8:24 AM Tomas Vondra > wrote: >> >> On Sun, Mar 29, 2020 at 10:16:53PM -0400, James Coleman wrote: >> >On Sun, Mar 29, 2020 at 9:44 PM Tomas Vondra >> > wrote: >> >> >> >> Hi, >> >> >> >> Attached is a slightly reorganized patch series. I've merged the fixes >> >> into the appropriate matches, and I've also combined the two patches >> >> adding incremental sort paths to additional places in planner. >> >> >> >> A couple more comments: >> >> >> >> >> >> 1) I think the GUC documentation in src/sgml/config.sgml is a bit too >> >> detailed, compared to the other enable_* GUCs. I wonder if there's a >> >> better place where to move the details. What about adding some examples >> >> and explanation to perform.sgml? >> > >> >I'll take a look at that and include in a patch series tomorrow. > >Attached. > >> >> 2) Looking at the explain output, the verbose mode looks like this: >> >> >> >> test=# explain (verbose, analyze) select a from t order by a, b, c; >> >> QUERY PLAN >> >> -------------------------------------------------------------------------------------------------------------------------------------------------------------- >> >> Gather Merge (cost=66.31..816072.71 rows=8333226 width=24) (actual time=4.787..20092.555 rows=10000000 loops=1) >> >> Output: a, b, c >> >> Workers Planned: 2 >> >> Workers Launched: 2 >> >> -> Incremental Sort (cost=66.28..729200.36 rows=4166613 width=24) (actual time=1.308..14021.575 rows=3333333 loops=3) >> >> Output: a, b, c >> >> Sort Key: t.a, t.b, t.c >> >> Presorted Key: t.a, t.b >> >> Full-sort Groups: 4169 Sort Method: quicksort Memory: avg=30kB peak=30kB >> >> Presorted Groups: 4144 Sort Method: quicksort Memory: avg=128kB peak=138kB >> >> Worker 0: actual time=0.766..16122.368 rows=3841573 loops=1 >> >> Full-sort Groups: 6871 Sort Method: quicksort Memory: avg=30kB peak=30kB >> >> Presorted Groups: 6823 Sort Method: quicksort Memory: avg=132kB peak=141kB >> >> Worker 1: actual time=1.986..16189.831 rows=3845490 loops=1 >> >> Full-sort Groups: 6874 Sort Method: quicksort Memory: avg=30kB peak=30kB >> >> Presorted Groups: 6847 Sort Method: quicksort Memory: avg=130kB peak=139kB >> >> -> Parallel Index Scan using t_a_b_idx on public.t (cost=0.43..382365.92 rows=4166613 width=24) (actual time=0.040..9808.449 rows=3333333 loops=3) >> >> Output: a, b, c >> >> Worker 0: actual time=0.048..11275.178 rows=3841573 loops=1 >> >> Worker 1: actual time=0.041..11314.133 rows=3845490 loops=1 >> >> Planning Time: 0.166 ms >> >> Execution Time: 25135.029 ms >> >> (22 rows) >> >> >> >> There seems to be missing indentation for the first line of worker info. >> > >> >Working on that too. > >See attached. I've folded in the original "explain fixes" patch into >the main series, and the "explain fixes" patch in this series contains >only the changes for the above. > Thanks. I'll take a look at those changes tomorrow. >> >> I'm still not quite convinced we should be printing two lines - I know >> >> you mentioned the lines might be too long, but see how long the other >> >> lines may get ... >> > >> >All right, I give in :) >> > >> >Do you think non-workers (both the leader and non-parallel plans) >> >should also move to one line? >> > >> >> I think we should use the same formatting for both cases, so yes. >> >> FWIW I forgot to mention I tweaked the INSTRUMENT_SORT_GROUP macro a >> bit, by moving the if condition in it. That makes the calls easier. > >Ah, that actually fixed some of the compile warnings. The other is >fixed in my explain fixes patch. > >> >> 3) I see the new nodes (plan state, ...) have "presortedCols" which does >> >> not indicate it's a "number of". I think we usually prefix names of such >> >> fields "n" or "num". What about "nPresortedCols"? (Nitpicking, I know.) >> > >> >I can fix this too. > >Changed everywhere we used this var name. I'm tempted to change to >nPresortedKeys, but a cursory glance suggests some cases might >actually be consistent with other var names reference columns, so I'm >not sure if we want to go down that path (and change more than just >this). > Not sure. We use "sort keys" and "path keys" for this, but I think "columns" is good enough. The main thing I've been working on today is benchmarking how this affects planning. And I'm seeing a regression that worries me a bit, unfortunately. The test I'm doing is pretty simple - build a small table with a bunch of columns: create table t (a int, b int, c int, d int, e int, f int, g int); insert into t select 100*random(), 100*random(), 100*random(), 100*random(), 100*random(), 100*random(), 100*random() from generate_series(1,100000) s(i); and then a number of indexes on subsets of up to 3 columns, as generated using the attached build-indexes.py script. And then run a bunch of explains (so no actual execution) sorting the data by at least 4 columns (to trigger incremental sort paths), measuring timing of the script. I did a bunch of runs on current master and v46 with incremental sort disabled and enabled, and the results look like this: master off on -------------------------- 34.609 37.463 37.729 which means about 8-9% regression with incremental sort. Of course, this is only for planning time, for execution the impact is going to be much smaller. But it's still a bit annoying. I've suspected this might be either due to the add_partial_path changes or the patch adding incremental sort to additional places, so I tested those parts individually and the answer is no - add_partial_path changes have very small impact (~1%, which might be noise). The regression comes mostly from the 0002 part that adds incremental sort. At least in this particular test - different tests might behave differently, of course. The annoying bit is that the overhead does not disappear after disabling incremental sort. That suggests this is not merely due to considering and creating higher number of paths, but due to something that happens before we even look at the GUC ... I think I've found one such place - if you look at compare_pathkeys, it has this check right before the forboth() loop: if (keys1 == keys2) return PATHKEYS_EQUAL; But with incremental sort we don't call pathkeys_contained_in, we call pathkeys_common_contained_in instead. And that does not call compare_pathkeys and does not have the simple equality check. Adding the following check seems to cut the overhead in half, which is nice: if (keys1 == keys2) { *n_common = list_length(keys1); return true; } Not sure where the rest of the regression comes from yet. Also, while looking at pathkeys_common_contained_in(), I've been a bit puzzled why does is this correct: return (key1 == NULL); It's easy to not notice it's key1 and not keys1, so I suggest we add a comment 'key1 == NULL' means we've processed whole keys1 list. regards -- Tomas Vondra http://www.2ndQuadrant.com PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services --gfn46hvoqmkpjtbs Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="build-indexes.py" #!/usr/bin/python import itertools columns = ['a', 'b', 'c', 'd', 'e', 'f', 'g']; indexes = [] for cols in itertools.permutations(columns): indexes.append(cols) for l in range(1,len(cols)): indexes.append(cols[:l]) indexes = set(indexes) for idx in indexes: if len(idx) < 4: print 'create index on t (' , (','.join(idx)) , ');' --gfn46hvoqmkpjtbs Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="run-test.py" #!/usr/bin/python import itertools import psycopg2 columns = ['a', 'b', 'c', 'd', 'e', 'f', 'g']; orderings = itertools.permutations(columns) conn = psycopg2.connect('host=localhost user=postgres dbname=test') cur = conn.cursor() cur.execute('set enable_incrementalsort = off') for o in orderings: if len(o) < 4: continue for r in range(1,10): cur.execute('EXPLAIN SELECT * FROM t ORDER BY ' + (','.join(o))) --gfn46hvoqmkpjtbs--