Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1t8YDx-004oTS-WB for pgsql-hackers@arkaria.postgresql.org; Wed, 06 Nov 2024 05:04:57 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1t8YDu-003Q9x-MS for pgsql-hackers@arkaria.postgresql.org; Wed, 06 Nov 2024 05:04:55 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1t8YDu-003Q9o-C3 for pgsql-hackers@lists.postgresql.org; Wed, 06 Nov 2024 05:04:54 +0000 Received: from mail-vk1-xa34.google.com ([2607:f8b0:4864:20::a34]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from ) id 1t8YDq-000Rlo-I6 for pgsql-hackers@lists.postgresql.org; Wed, 06 Nov 2024 05:04:54 +0000 Received: by mail-vk1-xa34.google.com with SMTP id 71dfb90a1353d-513de426719so369257e0c.0 for ; Tue, 05 Nov 2024 21:04:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1730869490; x=1731474290; darn=lists.postgresql.org; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=VJeJiMyWsUezfuDRJ1vp/lKGmLOvCxWVNY178akdH8M=; b=MVcyQWjuFstIzyqJaMHkMFhagrDMbR62g67DugI01HCOLuZoYwtyqE0/XXRG9JAYuq 9c3f1HTHTzLg9vvDLZoP9Qrw404PsokIk8lbpPvKKzRcVFfBUIXrqR6lgFppSDpjts9o fVI+AFHkb6u6keeRdLeNOucd+OQunAWx2vnD8UrmD5ZY+ZvS9cpvh/y6X/RboszBr65V 9Xehy3pXltKdpRpxi5VASt0k1VwYKojnbNleLlARaNhO2LxokbRmp8uWVuU8y1aAc3Q6 ejaP+w3bmz3O4/inPcw/kJTPIx69WdTNEJfMuWURjw755OuwjljUGdDQDWjAT5m+Dse3 utnA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1730869490; x=1731474290; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=VJeJiMyWsUezfuDRJ1vp/lKGmLOvCxWVNY178akdH8M=; b=UsBZhwof9SgcnDYkbBAOoWp11ECkbyAkUS8VWoALLNLIzMfosYP1G/4coF1Eul/uZN y6hsoDK8paQP3ysSOa7FtDFLw1IztcUjPQ2q0+cB0jQF0D7AKC2Db/K/hiHFSv61vrRx mrhgrDi4hYQMVWurBhnS0jJuLV35twUVPaHlrcFgU7jJHz2yib9XdNVJ670rl79QVy0P Qv9KLN8Abwpd4t3Z7qbMi1mfB7cWdW3TaXECSlvPEB7bjv/94w+61lbTWVZwg30/T9uA R1Gw2jJneTRNcvCpedwrGBT4CA96vKowEuuhY18QcH5rHo5GEShsN54xw9GfPHOtR8js YZuQ== X-Forwarded-Encrypted: i=1; AJvYcCUjeli7NeAYtLnHVCw5tnZXU0EYFE4fCnapYNSX5XCS+kU0dtvDAYO+hCl3bMg9N+gVA3JNFv0cenNlsk2j@lists.postgresql.org X-Gm-Message-State: AOJu0YzW9PhPUPEuv9ViLVH5r1wTkbdRJfv5SpQUneNuprGVAx+VLjiy KWS3+Eq5Ii1jcb+KeOHhRPTIzre2l2QT4XIU+dRYhpnaR6M8cOauGYeiYM4/vv+uE1jWjxscAWY 8uHDH+hJYkUAgmBjSeK/+9Lcjsv4= X-Google-Smtp-Source: AGHT+IF/Q8ZpGkbZwtR3fFrfHvw7/Bkj6s9xxaQ/eOIE3O5Z5SO8L+P2OxloiU1ZKmK4B5ZgbzJHSFxuTWLNiSfSq1I= X-Received: by 2002:a05:6102:38d1:b0:4a5:b159:8557 with SMTP id ada2fe7eead31-4a900e10f6emr24187234137.4.1730869489796; Tue, 05 Nov 2024 21:04:49 -0800 (PST) MIME-Version: 1.0 References: <87il22cj51.fsf@163.com> In-Reply-To: From: jian he Date: Wed, 6 Nov 2024 13:04:38 +0800 Message-ID: Subject: Re: Eager aggregation, take 3 To: Richard Guo Cc: Robert Haas , Paul George , Andy Fan , PostgreSQL-development , pgsql-hackers@lists.postgresql.org Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On Thu, Aug 29, 2024 at 10:26=E2=80=AFAM Richard Guo wrote: > > > > 2. I think there might be techniques we could use to limit planning > > effort at an earlier stage when the approach doesn't appear promising. > > For example, if the proposed grouping column is already unique, the > > exercise is pointless (I think). Ideally we'd like to detect that > > without even creating the grouped_rel. But the proposed grouping > > column might also be *mostly* unique. For example, consider a table > > with a million rows and a column 500,000 distinct values. I suspect it > > will be difficult for partial aggregation to work out to a win in a > > case like this, because I think that the cost of performing the > > partial aggregation will not reduce the cost either of the final > > aggregation or of the intervening join steps by enough to compensate. > > It would be best to find a way to avoid generating a lot of rels and > > paths in cases where there's really not much hope of a win. > > > > One could, perhaps, imagine going further with this by postponing > > eager aggregation planning until after regular paths have been built, > > so that we have good cardinality estimates. Suppose the query joins a > > single fact table to a series of dimension tables. The final plan thus > > uses the fact table as the driving table and joins to the dimension > > tables one by one. Do we really need to consider partial aggregation > > at every level? Perhaps just where there's been a significant row > > count reduction since the last time we tried it, but at the next level > > the row count will increase again? > > > > Maybe there are other heuristics we could use in addition or instead. > > Yeah, one of my concerns with this work is that it can use > significantly more CPU time and memory during planning once enabled. > It would be great if we have some efficient heuristics to limit the > effort. I'll work on that next and see what happens. > in v13, latest version. we can /* ... and initialize these targets */ if (!init_grouping_targets(root, rel, target, agg_input, &group_clauses, &group_exprs)) return NULL; if (rel->reloptkind =3D=3D RELOPT_BASEREL && group_exprs !=3D NIL) { foreach_node(Var, var, group_exprs) { if(var->varno =3D=3D rel->relid && has_unique_index(rel, var->varattno)) return NULL; } } since in init_grouping_targets we already Asserted that group_exprs is a list of Var. ---------------------------------------------------------------------------= ----- also in create_rel_agg_info, estimate_num_groups result->group_exprs =3D group_exprs; result->grouped_rows =3D estimate_num_groups(root, result->group_exprs, rel->rows, NULL, NULL); /* * The grouped paths for the given relation are considered useful i= ff * the row reduction ratio is greater than EAGER_AGGREGATE_RATIO. */ agg_info->agg_useful =3D (agg_info->grouped_rows <=3D rel->rows * (1 - EAGER_AGGREGATE_R= ATIO)); If the associated Var in group_exprs is too many, then result->grouped_rows will be less accurate, therefore agg_info->agg_useful will be less accurate= . should we limit the number of Var associated with Var group_exprs. for example: SET enable_eager_aggregate TO on; drop table if exists eager_agg_t1,eager_agg_t2, eager_agg_t3; CREATE TABLE eager_agg_t1 (a int, b int, c double precision); CREATE TABLE eager_agg_t2 (a int, b int, c double precision); INSERT INTO eager_agg_t1 SELECT i % 100, i, i FROM generate_series(1, 5)i; INSERT INTO eager_agg_t2 SELECT i % 10, i, i FROM generate_series(1, 5)i; INSERT INTO eager_agg_t2 SELECT i % 10, i, i FROM generate_series(-4, -2)i; explain(costs off, verbose, settings) SELECT t1.a, avg(t2.c) FROM eager_agg_t1 t1 JOIN eager_agg_t2 t2 ON abs(t1.b) =3D abs(t2.b % 10 + t2.a) group by 1; explain(costs off, verbose, settings) SELECT t1.a, avg(t2.c) FROM eager_agg_t1 t1 JOIN eager_agg_t2 t2 ON abs(t1.b) =3D abs(t2.b % 10 + t2.a) group by 1; QUERY PLAN ---------------------------------------------------------------------------= ----------- Finalize HashAggregate Output: t1.a, avg(t2.c) Group Key: t1.a -> Merge Join Output: t1.a, (PARTIAL avg(t2.c)) Merge Cond: ((abs(((t2.b % 10) + t2.a))) =3D (abs(t1.b))) -> Sort Output: t2.b, t2.a, (PARTIAL avg(t2.c)), (abs(((t2.b % 10) + t2.a))) Sort Key: (abs(((t2.b % 10) + t2.a))) -> Partial HashAggregate Output: t2.b, t2.a, PARTIAL avg(t2.c), abs(((t2.b % 10) + t2.a)) Group Key: t2.b, t2.a -> Seq Scan on public.eager_agg_t2 t2 Output: t2.a, t2.b, t2.c -> Sort Output: t1.a, t1.b, (abs(t1.b)) Sort Key: (abs(t1.b)) -> Seq Scan on public.eager_agg_t1 t1 Output: t1.a, t1.b, abs(t1.b) Settings: enable_eager_aggregate =3D 'on' Query Identifier: -734044107933323262