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 1iiEOr-0006Cp-6o for pgsql-hackers@arkaria.postgresql.org; Fri, 20 Dec 2019 09:16:45 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1iiEOn-00043H-KR for pgsql-hackers@arkaria.postgresql.org; Fri, 20 Dec 2019 09:16:41 +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 1iiEOn-00043A-B5 for pgsql-hackers@lists.postgresql.org; Fri, 20 Dec 2019 09:16:41 +0000 Received: from mx0a-00296801.pphosted.com ([148.163.150.38]) by magus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1iiEOj-00076O-12 for pgsql-hackers@postgresql.org; Fri, 20 Dec 2019 09:16:40 +0000 Received: from pps.filterd (m0114582.ppops.net [127.0.0.1]) by mx0a-00296801.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id xBK9CiHM016444 for ; Fri, 20 Dec 2019 09:16:32 GMT Received: from mail-pf1-f197.google.com (mail-pf1-f197.google.com [209.85.210.197]) by mx0a-00296801.pphosted.com with ESMTP id 2wyns0hq3u-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Fri, 20 Dec 2019 09:16:32 +0000 Received: by mail-pf1-f197.google.com with SMTP id i196so5755233pfe.6 for ; Fri, 20 Dec 2019 01:16:32 -0800 (PST) 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=6tdSAgVWnAqv5HpHr7clJKmXsEkROibw/u8pLRFVOM4=; b=ZsTEptTOMP+fRswY98eCgPqIfmLti3uEFjy163ptUUOtxyh7VVNUx1SGPw8v/UmZkv QXrm1fUVYSrya1rPdMlP+fvG4ndynzhT+myfho5hYELaWIjnbcTRNZepicsVBDPvh9LG LMv8NhOh9RMPysMmQUmBRRxOLixVR+xEc+DeEbQX+Q7FQXZZD6LPWclhPeULhhSJq7y2 dMkHq1FCWIwv1/iXuWdIVkph9pARnLO16lHQmEU9YecmsFRKp7cHhjWp+noBlC061Vo2 R9rrsEt96OuUimjlA66IM6rUPPxI5M9j4bsUQXamtV5g7uCZLBMbdo7a0IV191DdVVPa EytA== X-Gm-Message-State: APjAAAWDFfV2nTMPQtNevmpA5TIZ9+mZQp2TY/oClglQgdSq3ktKK6kd NiLswNY6fSmSpQ6VI4Vh3UVcZK/bSnkBBvytqaGmCSTxIAnoSdyIvSIMOfjZIgnDejPkVVuUAVI uBSYnW2aoDB8JLcpnXy67cHHMhcfi6mRWM03GYYDLCvZjhKSw3g== X-Received: by 2002:a62:7883:: with SMTP id t125mr15268581pfc.141.1576833391805; Fri, 20 Dec 2019 01:16:31 -0800 (PST) X-Google-Smtp-Source: APXvYqwJ5eifzLbLyQ7l2Q2zg+3nm3ciuHiXyLQhQMKzQFuFoDSCyUoavofpKMwZa7WESz5xyepgLQ== X-Received: by 2002:a62:7883:: with SMTP id t125mr15268547pfc.141.1576833391519; Fri, 20 Dec 2019 01:16:31 -0800 (PST) Received: from localhost (li1619-9.members.linode.com. [172.104.39.9]) by smtp.gmail.com with ESMTPSA id 11sm12023742pfz.25.2019.12.20.01.16.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Dec 2019 01:16:30 -0800 (PST) Date: Fri, 20 Dec 2019 17:16:26 +0800 From: Adam Lee To: Tomas Vondra Cc: Jeff Davis , Taylor Vesely , Melanie Plageman , pgsql-hackers@postgresql.org Subject: Re: Memory-Bounded Hash Aggregation Message-ID: <20191220091626.GD45905@mars.local> References: <20190703001753.s5e5cme3ucjgeu6c@development> <20190711155520.zqipi23o3yybx7ym@development> <9be86fc1adc315f69b8af4b379087ab451008d8a.camel@j-davis.com> <20190802064405.GA94036@mars.local> <617fea8258ba3df7bc8b21cd7f3afc219f2383d9.camel@j-davis.com> <20190802152123.ichmacgx3y3x7dc3@development> <20191214173225.3kzsbncr6brpxdll@development> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="sHrvAb52M6C8blB9" Content-Disposition: inline In-Reply-To: <20191214173225.3kzsbncr6brpxdll@development> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.95,18.0.572 definitions=2019-12-19_08:2019-12-17,2019-12-19 signatures=0 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 adultscore=0 malwarescore=0 impostorscore=0 spamscore=0 mlxscore=0 priorityscore=1501 suspectscore=2 mlxlogscore=999 lowpriorityscore=0 bulkscore=0 phishscore=0 clxscore=1015 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-1910280000 definitions=main-1912200074 List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk --sHrvAb52M6C8blB9 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Sat, Dec 14, 2019 at 06:32:25PM +0100, Tomas Vondra wrote: > I've done a bit more testing on this, after resolving a couple of minor > conflicts due to recent commits (rebased version attached). > > In particular, I've made a comparison with different dataset sizes, > group sizes, GUC settings etc. The script and results from two different > machines are available here: > > The script essentially runs a simple grouping query with different > number of rows, groups, work_mem and parallelism settings. There's > nothing particularly magical about it. Nice! > I did run it both on master and patched code, allowing us to compare > results and assess impact of the patch. Overall, the changes are > expected and either neutral or beneficial, i.e. the timing are the same > or faster. > > The number of cases that regressed is fairly small, but sometimes the > regressions are annoyingly large - up to 2x in some cases. Consider for > example this trivial example with 100M rows: I suppose this is because the patch has no costing changes yet. I hacked a little to give hash agg a spilling punish, just some value based on (groups_in_hashtable * num_of_input_tuples)/num_groups_from_planner, it would not choose hash aggregate in this case. However, that punish is wrong, because comparing to the external sort algorithm, hash aggregate has the respilling, which involves even more I/O, especially with a very large number of groups but a very small number of tuples in a single group like the test you did. It would be a challenge. BTW, Jeff, Greenplum has a test for hash agg spill, I modified a little to check how many batches a query uses, it's attached, not sure if it would help. -- Adam Lee --sHrvAb52M6C8blB9 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="hashagg_spill.sql" create schema hashagg_spill; set search_path to hashagg_spill; -- start_ignore CREATE EXTENSION plpythonu; -- end_ignore -- Create a function which checks how many batches there are -- output example: "Memory Usage: 4096kB Batches: 68 Disk Usage:8625kB" create or replace function hashagg_spill.num_batches(explain_query text) returns setof int as $$ import re rv = plpy.execute(explain_query) search_text = 'batches' result = [] for i in range(len(rv)): cur_line = rv[i]['QUERY PLAN'] if search_text.lower() in cur_line.lower(): p = re.compile('.*Memory Usage: (\d+).* Batches: (\d+) Disk.*') m = p.match(cur_line) batches = int(m.group(2)) result.append(batches) return result $$ language plpythonu; create table testhagg (i1 int, i2 int, i3 int, i4 int); insert into testhagg select i,i,i,i from generate_series(1, 30000)i; set work_mem="1800"; select * from (select max(i1) from testhagg group by i2) foo order by 1 limit 10; select num_batches > 0 from hashagg_spill.num_batches('explain (analyze, verbose) select max(i1) from testhagg group by i2;') num_batches; select num_batches > 3 from hashagg_spill.num_batches('explain (analyze, verbose) select max(i1) from testhagg group by i2 limit 90000;') num_batches; reset all; set search_path to hashagg_spill; -- Test agg spilling scenarios create table aggspill (i int, j int, t text); insert into aggspill select i, i*2, i::text from generate_series(1, 10000) i; insert into aggspill select i, i*2, i::text from generate_series(1, 100000) i; insert into aggspill select i, i*2, i::text from generate_series(1, 1000000) i; -- No spill with large statement memory set work_mem = '125MB'; select * from hashagg_spill.num_batches('explain (analyze, verbose) select count(*) from (select i, count(*) from aggspill group by i,j having count(*) = 1) g;'); -- Reduce the statement memory to induce spilling set work_mem = '10MB'; select num_batches > 32 from hashagg_spill.num_batches('explain (analyze, verbose) select count(*) from (select i, count(*) from aggspill group by i,j having count(*) = 2) g;') num_batches; -- Reduce the statement memory, more batches set work_mem = '5MB'; select num_batches > 64 from hashagg_spill.num_batches('explain (analyze, verbose) select count(*) from (select i, count(*) from aggspill group by i,j having count(*) = 3) g;') num_batches; -- Check spilling to a temp tablespace SET work_mem='1000kB'; CREATE TABLE hashagg_spill(col1 numeric, col2 int); INSERT INTO hashagg_spill SELECT id, 1 FROM generate_series(1,20000) id; ANALYZE hashagg_spill; CREATE TABLE spill_temptblspace (a numeric); SET temp_tablespaces=pg_default; INSERT INTO spill_temptblspace SELECT avg(col2) col2 FROM hashagg_spill GROUP BY col1 HAVING(sum(col1)) < 0; RESET temp_tablespaces; RESET work_mem; drop schema hashagg_spill cascade; --sHrvAb52M6C8blB9--