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 1oJ8mH-0003kq-L0 for pgsql-hackers@arkaria.postgresql.org; Wed, 03 Aug 2022 07:26:49 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1oJ8mF-0007Ob-Hq for pgsql-hackers@arkaria.postgresql.org; Wed, 03 Aug 2022 07:26:47 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1oJ8mF-0007Mf-6w for pgsql-hackers@lists.postgresql.org; Wed, 03 Aug 2022 07:26:47 +0000 Received: from mail-wr1-x42a.google.com ([2a00:1450:4864:20::42a]) by makus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1oJ8mC-0006R0-2O for pgsql-hackers@lists.postgresql.org; Wed, 03 Aug 2022 07:26:45 +0000 Received: by mail-wr1-x42a.google.com with SMTP id l22so20480113wrz.7 for ; Wed, 03 Aug 2022 00:26:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=aiven.io; s=google; h=content-transfer-encoding:mime-version:organization:message-id:date :subject:to:from:from:to:cc; bh=Mwl2NWfA28G+T3zDKM3BK6OuSUcpNT66I3LxJowtGoc=; b=SEOejnZKccBSK0INp7k/mJmZmOQoVMFYqhINdw9JBE8qQ4+acFy0ZT0p+RICAyIcoE LGnxkfRD37vlnoG6801fsb1mAxHvAJBpCPpsdmuFYsoFRDTh6UiSE8oNJRpiQpY7xDPs FJOZbMAuQKByqH4xj1KOwm+QE6It2KhrZzLmE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:organization:message-id:date :subject:to:from:x-gm-message-state:from:to:cc; bh=Mwl2NWfA28G+T3zDKM3BK6OuSUcpNT66I3LxJowtGoc=; b=kcpQCC+OFcpyL8ewO4rUCMmYUoRTJ07LbbUUl2RIgXhWYYMNahTYxSXluxi58l+7lk VmT8YhobufZJiLU7ios2izl66ILdcVWiG/Xsk7TxfAF3qIrGHRUy9HpUkDODtrg/HIM3 OY5rxXa+bcvyW/NPBh3deNmMk0K4j/KRourEJN5iV9cEcAKyzGN6vMpV7+u7wj0ehRqG 1O+SldL1sJWlfEut9Tqa4AQRax5XDluUJQnLttUTTLYyxWb3u8AgIvzuMttNkvGzLasU voTwUG/pROliqV9B4RS461Pafx22yfsy5YaUzlrnga5bg86xlvTbZsBqMU8XRuBx0BVa 4H5A== X-Gm-Message-State: ACgBeo0rkt6jPYDTjCNHeQyKm40vi0CMiGhTEWP2Phh6JJVvyC6aspQO +PDFysnFhWeY5Wy/5jbIysTWLhaPPqn7ri7y2OkndhluFvHQ0fsqwZMRZWt+LLfKYATyExvmUKl 3hPZA0RbRYAYv2m0aMuNr9jdCfwVSRNtimMio63ZuFn3xHKtGh+j10feDI5Q1fCsO2cP2+40nVj E/eT6Eo9m1taMqfg== X-Google-Smtp-Source: AA6agR4TPdUMHHauiqUC8Ey0PHIeZq6l4B7o8nV6H+wclWfo1QKSPPdGp6v67yCzDFhMdcjJk3Up+A== X-Received: by 2002:adf:f38b:0:b0:21e:c041:7726 with SMTP id m11-20020adff38b000000b0021ec0417726mr15121768wro.394.1659511601636; Wed, 03 Aug 2022 00:26:41 -0700 (PDT) Received: from aivenronan.localnet ([45.13.105.93]) by smtp.gmail.com with ESMTPSA id g17-20020a5d4891000000b0021f0558e51asm17542428wrq.55.2022.08.03.00.26.40 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 03 Aug 2022 00:26:40 -0700 (PDT) From: Ronan Dunklau To: pgsql-hackers@lists.postgresql.org Subject: Fix gin index cost estimation Date: Wed, 03 Aug 2022 09:26:32 +0200 Message-ID: <3188617.44csPzL39Z@aivenronan> Organization: aiven MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="nextPart8098553.T7Z3S40VBb" Content-Transfer-Encoding: 7Bit 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. --nextPart8098553.T7Z3S40VBb Content-Transfer-Encoding: 7Bit Content-Type: text/plain; charset="us-ascii" Hello, Following the bug report at [1], I sent the attached patch to pgsql-bugs mailing list. I'm starting a thread here to add it to the next commitfest. The problem I'm trying to solve is that, contrary to btree, gist and sp-gist indexes, gin indexes do not charge any cpu-cost for descending the entry tree. This can be a problem in cases where the io cost is very low. This can happen with manual tuning of course, but more surprisingly when the the IO cost is amortized over a large number of iterations in a nested loop. In that case, we basically consider it free since everything should already be in the shared buffers. This leads to some inefficient plans, as an equivalent btree index should be picked instead. This has been discovered in PG14, as this release makes it possible to use a pg_trgm gin index with the equality operator. Before that, only the btree would have been considered and as such the discrepancy in the way we charge cpu cost didn't have noticeable effects. However, I suspect users of btree_gin could have the same kind of problems in prior versions. Best regards, [1]: https://www.postgresql.org/message-id/flat/ 2187702.iZASKD2KPV%40aivenronan#0c2498c6a85e31a589b3e9a6a3616c52 -- Ronan Dunklau --nextPart8098553.T7Z3S40VBb Content-Disposition: attachment; filename="v1-0001-Fix-gin-costing.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="UTF-8"; name="v1-0001-Fix-gin-costing.patch" From 0aa1ff24e58234d759c07f4eeec163a82244be25 Mon Sep 17 00:00:00 2001 From: Ronan Dunklau Date: Wed, 6 Jul 2022 17:29:01 +0200 Subject: [PATCH v1] Fix gin costing. GIN index scans were not taking any descent CPU-based cost into account. That made them look cheaper than other types of indexes when they shouldn't be. We use the same heuristic as for btree indexes, but multiplying it by the number of searched entries. Per report of Hung Nguyen. --- src/backend/utils/adt/selfuncs.c | 36 +++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index fa1f589fad..21407c3d38 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -7425,6 +7425,7 @@ gincostestimate(PlannerInfo *root, IndexPath *path, double loop_count, qual_arg_cost, spc_random_page_cost, outer_scans; + Cost descentCost; Relation indexRel; GinStatsData ginStats; ListCell *lc; @@ -7524,6 +7525,18 @@ gincostestimate(PlannerInfo *root, IndexPath *path, double loop_count, &spc_random_page_cost, NULL); + + /* + * We model index descent costs similarly to those for btree, but we also + * need an idea of the tree_height. + * We use numEntries / numEntryPages as the fanout factor. + */ + if (index->tree_height < 0) + { + index->tree_height = ceil(log(numEntries) / log(numEntries / numEntryPages)); + } + + /* * Generic assumption about index correlation: there isn't any. */ @@ -7649,6 +7662,27 @@ gincostestimate(PlannerInfo *root, IndexPath *path, double loop_count, */ dataPagesFetched = ceil(numDataPages * partialScale); + + *indexStartupCost = 0; + + /* + * Add a CPU-cost component similar to btree to represent the costs of the + * initial descent. + * We charge descentCost once for every entry + */ + if (numTuples > 1) + { + descentCost = ceil(log(numTuples) / log(2.0)) * cpu_operator_cost; + *indexStartupCost += descentCost * counts.searchEntries; + } + + /* + * Add a similar per-page charge, depending on the tree heights. + */ + descentCost = (index->tree_height + 1) * 50.0 * cpu_operator_cost; + *indexStartupCost += descentCost * counts.searchEntries; + + /* * Calculate cache effects if more than one scan due to nestloops or array * quals. The result is pro-rated per nestloop scan, but the array qual @@ -7672,7 +7706,7 @@ gincostestimate(PlannerInfo *root, IndexPath *path, double loop_count, * Here we use random page cost because logically-close pages could be far * apart on disk. */ - *indexStartupCost = (entryPagesFetched + dataPagesFetched) * spc_random_page_cost; + *indexStartupCost += (entryPagesFetched + dataPagesFetched) * spc_random_page_cost; /* * Now compute the number of data pages fetched during the scan. -- 2.37.0 --nextPart8098553.T7Z3S40VBb--