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 1rUD9Q-009YOg-2H for pgsql-hackers@arkaria.postgresql.org; Sun, 28 Jan 2024 21:57:17 +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 1rUD9P-00A8Gz-7G for pgsql-hackers@arkaria.postgresql.org; Sun, 28 Jan 2024 21:57:15 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1rUD9O-00A8Gj-4j for pgsql-hackers@lists.postgresql.org; Sun, 28 Jan 2024 21:57:14 +0000 Received: from mail-ej1-x62f.google.com ([2a00:1450:4864:20::62f]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from ) id 1rUD9H-003rN4-ID for pgsql-hackers@lists.postgresql.org; Sun, 28 Jan 2024 21:57:12 +0000 Received: by mail-ej1-x62f.google.com with SMTP id a640c23a62f3a-a349ed467d9so209443366b.1 for ; Sun, 28 Jan 2024 13:57:07 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=enterprisedb.com; s=google; t=1706479024; x=1707083824; darn=lists.postgresql.org; h=to:subject:from:content-language:user-agent:mime-version:date :message-id:from:to:cc:subject:date:message-id:reply-to; bh=sGEQESxtrVigb0zZz1xM3uCj+tsIND1j/1CVWmHMS+c=; b=UttwV6aX80yZf4uL8iZuAbIRsdIOgVqF/9zXv+R7xe9rNoSjOFD8FYOjVXXaQ4FIwL s9rUqeMcPgUi6rpxBlzGgbFPkgyBH/hejTXmD9TlTdNpR/2TGjyVqo28dvbCcO+CH5iS axrwidUY77ZJLl4Xi/1ddHV8H9nx1n8C3gRwlWif/AoffiwwvIeC58NDOjvTMoWCkDgh 6piIwXEWsp9+DU76Vl1OUgB4xKu1ofpAs9FwaLkPZv0qur8jSaR1oEPpQhPQA9SDYxrE rbZk01kLBhjgYK0lUrfy59jTl5fgwyvRlD/TWBruZ10Qxr3xiFVaBZy/7EJKFMIihp5M 8Zdg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1706479024; x=1707083824; h=to:subject:from:content-language:user-agent:mime-version:date :message-id:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=sGEQESxtrVigb0zZz1xM3uCj+tsIND1j/1CVWmHMS+c=; b=cijf0hLkq/joqIBlfo0nbVQd1K+HyG4MudJKktQj2EVA+uj6iN+pUqYa2CvrTNYevA /vAdGPYQ2qpCdVTWgk4JbWvThXGnpNGmv3B7uOpuBVdVyed9GInxWRNRI8g2osyFBO1N ug6ec7uuTKsogOTmlU7ZSN8DuANMNNI20BnZlQ7mb2HiVJzyiwhDIfFwrw9rCWjsgm/4 AuVJ4FWmaSIsqY80DgMW53mVlBoWaTRlY/OVErP4AaMl9EA9KxFvXAJaqc9FLr8AZzx5 MQXeyu2UlHpQvH4rHtK9+/foHWjmOk7XsGYAW0mjXRavZKtU5JWWOpRaSsO+xzsrq5g9 Jk6g== X-Gm-Message-State: AOJu0YxltZJT/uoG9zqYmzgqX2rxANNR7G36v6Vp5k3kArhFnbCqG01e LjOtOuKWrN6lFsRmXxtkirAGC7gdRdxhoI1KaQd5xs5U9/bY8BFqFzaHiGSfmUu5Gq28f9V+4Fj aREOqGCZpMLEZp0rjOEO/9KaYpYFzuMKViS5eu/ev/UQcdgbKQ0nhekILgU32ExmP17WhvDEH+D IEV+5hnJt+53yS43tguNrUXfvockOUxPJQmZAYc917E0GQU/I1vRJApEAjJ3qa3g== X-Google-Smtp-Source: AGHT+IH0F7ud+slDW8aN3UQ0KkYQxarwzl8NCKxDUt0yDsjxH6Tw7rKyFIUQhHue/OKpub7g/1A+Mw== X-Received: by 2002:a17:906:a14b:b0:a35:c95f:55ef with SMTP id bu11-20020a170906a14b00b00a35c95f55efmr192790ejb.69.1706479023532; Sun, 28 Jan 2024 13:57:03 -0800 (PST) Received: from [10.137.0.18] (ip-86-49-229-30.bb.vodafone.cz. [86.49.229.30]) by smtp.gmail.com with ESMTPSA id r16-20020a170906281000b00a35becf3f0csm264208ejc.85.2024.01.28.13.57.02 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sun, 28 Jan 2024 13:57:02 -0800 (PST) Content-Type: multipart/mixed; boundary="------------lpCK44YE9gLx0pYZsM2wRAQO" Message-ID: <510b887e-c0ce-4a0c-a17a-2c6abb8d9a5c@enterprisedb.com> Date: Sun, 28 Jan 2024 22:57:02 +0100 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Content-Language: en-US From: Tomas Vondra Subject: scalability bottlenecks with (many) partitions (and more) To: PostgreSQL Hackers List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk This is a multi-part message in MIME format. --------------lpCK44YE9gLx0pYZsM2wRAQO Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit Hi, I happened to investigate a query involving a partitioned table, which led me to a couple of bottlenecks severely affecting queries dealing with multiple partitions (or relations in general). After a while I came up with three WIP patches that improve the behavior by an order of magnitude, and not just in some extreme cases. Consider a partitioned pgbench with 20 partitions, say: pgbench -i -s 100 --partitions 100 testdb but let's modify the pgbench_accounts a little bit: ALTER TABLE pgbench_accounts ADD COLUMN aid_parent INT; UPDATE pgbench_accounts SET aid_parent = aid; CREATE INDEX ON pgbench_accounts(aid_parent); VACUUM FULL pgbench_accounts; which simply adds "aid_parent" column which is not a partition key. And now let's do a query SELECT * FROM pgbench_accounts pa JOIN pgbench_branches pb ON (pa.bid = pb.bid) WHERE pa.aid_parent = :aid so pretty much the regular "pgbench -S" except that on the column that does not allow partition elimination. Now, the plan looks like this: QUERY PLAN ---------------------------------------------------------------------- Hash Join (cost=1.52..34.41 rows=10 width=465) Hash Cond: (pa.bid = pb.bid) -> Append (cost=0.29..33.15 rows=10 width=101) -> Index Scan using pgbench_accounts_1_aid_parent_idx on pgbench_accounts_1 pa_1 (cost=0.29..3.31 rows=1 width=101) Index Cond: (aid_parent = 3489734) -> Index Scan using pgbench_accounts_2_aid_parent_idx on pgbench_accounts_2 pa_2 (cost=0.29..3.31 rows=1 width=101) Index Cond: (aid_parent = 3489734) -> Index Scan using pgbench_accounts_3_aid_parent_idx on pgbench_accounts_3 pa_3 (cost=0.29..3.31 rows=1 width=101) Index Cond: (aid_parent = 3489734) -> Index Scan using pgbench_accounts_4_aid_parent_idx on pgbench_accounts_4 pa_4 (cost=0.29..3.31 rows=1 width=101) Index Cond: (aid_parent = 3489734) -> ... -> Hash (cost=1.10..1.10 rows=10 width=364) -> Seq Scan on pgbench_branches pb (cost=0.00..1.10 rows=10 width=364) So yeah, scanning all 100 partitions. Not great, but no partitioning scheme is perfect for all queries. Anyway, let's see how this works on a big AMD EPYC machine with 96/192 cores - with "-M simple" we get: parts 1 8 16 32 64 96 160 224 ----------------------------------------------------------------------- 0 13877 105732 210890 410452 709509 844683 1050658 1163026 100 653 3957 7120 12022 12707 11813 10349 9633 1000 20 142 270 474 757 808 567 427 These are transactions per second, for different number of clients (numbers in the header). With -M prepared the story doesn't change - the numbers are higher, but the overall behavior is pretty much the same. Firstly, with no partitions (first row), the throughput by ~13k/client initially, then it gradually levels off. But it grows all the time. But with 100 or 1000 partitions, it peaks and then starts dropping again. And moreover, the throughput with 100 or 1000 partitions is just a tiny fraction of the non-partitioned value. The difference is roughly equal to the number of partitions - for example with 96 clients, the difference between 0 and 1000 partitions is 844683/808 = 1045. I could demonstrate the same behavior with fewer partitions - e.g. with 10 partitions you get ~10x difference, and so on. Another thing I'd mention is that this is not just about partitioning. Imagine a star schema with a fact table and dimensions - you'll get the same behavior depending on the number of dimensions you need to join with. With "-M simple" you may get this, for example: dims 1 8 16 32 64 96 160 224 ---------------------------------------------------------------------- 1 11737 92925 183678 361497 636598 768956 958679 1042799 10 462 3558 7086 13889 25367 29503 25353 24030 100 4 31 61 122 231 292 292 288 So, similar story - significant slowdown as we're adding dimensions. Now, what could be causing this? Clearly, there's a bottleneck of some kind, and we're hitting it. Some of this may be simply due to execution doing more stuff (more index scans, more initialization, ...) but maybe not - one of the reasons why I started looking into this was not using all the CPU even for small scales - the CPU was maybe 60% utilized. So I started poking at things. The first thing that I thought about was locking, obviously. That's consistent with the limited CPU utilization (waiting on a lock = not running), and it's somewhat expected when using many partitions - we need to lock all of them, and if we have 100 or 1000 of them, that's potentially lot of locks.