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 1uHdH6-006G5s-OJ for pgsql-hackers@arkaria.postgresql.org; Wed, 21 May 2025 06:50:01 +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 1uHdH5-003lNh-Jm for pgsql-hackers@arkaria.postgresql.org; Wed, 21 May 2025 06:49:59 +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 1uHdH4-003lLz-Oe for pgsql-hackers@lists.postgresql.org; Wed, 21 May 2025 06:49:59 +0000 Received: from m16.mail.163.com ([117.135.210.5]) by magus.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1uHdGx-0005Mw-20 for pgsql-hackers@lists.postgresql.org; Wed, 21 May 2025 06:49:56 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:To:Subject:Date:Message-ID:MIME-Version: Content-Type; bh=L5U8NS6im5F5nrOkgUxEFf6GUlzLKf8SbsWqfnHkpjw=; b=f2y7p/Sm5EbdaSQlk8e8xJKqPps50Wz1cOUyIvDRcoNFpZxbiiW09nVasf/jeU 4NXpbLkf8jujzWgg0ikVfbGdVJ2dJKF6+kd0c/DNj7brgoMX6vKu8QFO7A4hrVCA I/s4prJARlvue9tOcFPRcH8q/iwfc7iMBIjbzzx25GaDw= Received: from lovely-coding (unknown []) by gzga-smtp-mtada-g0-0 (Coremail) with SMTP id _____wDX7_Z4dy1ofXd5Cw--.10048S3; Wed, 21 May 2025 14:49:45 +0800 (CST) From: Andy Fan To: Postgres hackers Cc: Robert Haas Subject: parallel_safe Date: Wed, 21 May 2025 14:49:28 +0800 Message-ID: <87ecwisbk7.fsf@163.com> MIME-Version: 1.0 Content-Type: text/plain X-CM-TRANSID: _____wDX7_Z4dy1ofXd5Cw--.10048S3 X-Coremail-Antispam: 1Uf129KBjvJXoWxWry8Xry7Xw13WF43XFWUJwb_yoWrWw13pF 1agryayw1kGr1UCw18Zr48JF17Aw1kXrnxJF1rKr1vyw45Ar10qF1IkF4xZFWjgrW8Za9Y qF4UKw1ru3sxAa7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x0zRPfH8UUUUU= X-Originating-IP: [101.227.46.168] X-CM-SenderInfo: x2klx3xlid0iqsrtqiywtou0bp/xtbBzwRUU2gtdkIe-AAAsf List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk Hi, In the comments of add_partial_path, we have: * We don't generate parameterized partial paths for several reasons. Most * importantly, they're not safe to execute, because there's nothing to * make sure that a parallel scan within the parameterized portion of the * plan is running with the same value in every worker at the same time. and we are using 'is_parallel_safe(PlannerInfo *root, Node *node)' to see if it is safe/necessary to generate partial path on a RelOptInfo. In the code of 'is_parallel_safe': /* * We can't pass Params to workers at the moment either, so they are also * parallel-restricted, unless they are PARAM_EXTERN Params or are * PARAM_EXEC Params listed in safe_param_ids... */ else if (IsA(node, Param)) { Param *param = (Param *) node; if (param->paramkind == PARAM_EXTERN) return false; if (param->paramkind != PARAM_EXEC || !list_member_int(context->safe_param_ids, param->paramid)) { if (max_parallel_hazard_test(PROPARALLEL_RESTRICTED, context)) return true; } return false; /* nothing to recurse to */ } Then see the below example: create table bigt (a int, b int, c int); insert into bigt select i, i, i from generate_series(1, 1000000)i; analyze bigt; select * from bigt o where b = 1; QUERY PLAN ----------------------------------- Gather Workers Planned: 2 -> Parallel Seq Scan on bigt o Filter: (b = 1) (4 rows) select * from bigt o where b = 1 and c = (select sum(c) from bigt i where c = o.c); QUERY PLAN ------------------------------------------- Seq Scan on bigt o Filter: ((b = 1) AND (c = (SubPlan 1))) SubPlan 1 -> Aggregate -> Seq Scan on bigt i Filter: (c = o.c) (6 rows) I think the below plan should be correct and more efficiently. Plan 1: QUERY PLAN ------------------------------------------------- Gather Workers Planned: 2 -> Parallel Seq Scan on bigt o Filter: ((b = 1) AND (c = (SubPlan 1))) SubPlan 1 -> Aggregate -> Seq Scan on bigt Filter: (c = o.c) (8 rows) However the above plan is impossible because: (1). During the planning of the SubPlan, we use is_parallel_safe() to set the "bigt i"'s consider_parallel to false because of the above "PARAM_EXEC" reason. (2). The parallel_safe of the final SubPlan is set to false due to rel->consider_parallel. (3). During the planning of "bigt o", it calls is_parallel_safe and then it find a subplan->parallel_safe == false, then all the partial path is impossible. is_parallel_safe/max_parallel_hazard_walker: else if (IsA(node, SubPlan)) { SubPlan *subplan = (SubPlan *) node; List *save_safe_param_ids; if (!subplan->parallel_safe && max_parallel_hazard_test(PROPARALLEL_RESTRICTED, context)) return true; ... } So if we think "plan 1" is valid, then what is wrong? I think it is better to think about what parallel_safe is designed for. In Path: /* OK to use as part of parallel plan? */ bool parallel_safe; The definition looks to say: the Path/Plan should not be run as a 'parallel_aware' plan, but the code looks to say: The Path/Plan should not be run in a parallel worker even it is *not* parallel_aware. The reason I feel the above is because: * We don't generate parameterized partial paths for several reasons. Most * importantly, they're not safe to execute, because there's nothing to * make sure that a parallel scan within the parameterized portion of the * plan is running with the same value in every worker at the same time. If a plan which is not parallel-aware, why should we care about the above stuff? In the current code, there are some other parallel_safe = false which look like a *should not be run in a parallel worker rather than parallel plan*. the cases I know are: 1. path->parallel_safe = false in Gather/GatherMerge. 2. some expressions which is clearly claried as parallel unsafe. So parallel_safe looks have two different meaning to me. are you feeling something similar? Do you think treating the different parallel_safe would make parallel works in some more places? Do you think the benefits would be beyond the SubPlan one (I can't make a example beside SubPlan so far). -- Best Regards Andy Fan