From ca5342a2ceb2adfc867971c80e3bd0a16ccab3aa Mon Sep 17 00:00:00 2001 From: Vaibhav Dalvi Date: Mon, 31 Aug 2026 10:59:23 +0000 Subject: [PATCH] Drop equality operator support from gist_trgm_ops The planner's generic, selectivity-based cost model for GiST index scans has no way to see that gtrgm_consistent()'s containment check for '=' can be a false positive at a signature-tree node regardless of how selective the query value actually is (a short query value with few trigrams is especially prone to this). This can make the planner choose a gist_trgm_ops index over a much cheaper btree index for a plain equality lookup, by orders of magnitude in real execution time, with no way for the user to see it coming. gin_trgm_ops does not have this problem: GIN's cost estimator was fixed to use real per-key statistics in commit cd9479af2af ("Improve GIN cost estimation"). GiST's estimator has no analogous fix, so until it does, stop offering '=' via gist_trgm_ops specifically. gin_trgm_ops is unaffected and keeps supporting the operator. LIKE, ILIKE, and the similarity operators on gist_trgm_ops are unaffected; they were registered independently of this operator and predate it. Discussion: https://postgr.es/m/CAOBaU_YWwtT7tdggtROacjdOdeYHCz-tmSwuC-j-TOG-g97J0w@mail.gmail.com --- contrib/pg_trgm/Makefile | 6 +++--- contrib/pg_trgm/pg_trgm--1.6--1.7.sql | 19 +++++++++++++++++++ contrib/pg_trgm/pg_trgm.control | 2 +- doc/src/sgml/pgtrgm.sgml | 14 +++++++++----- 4 files changed, 32 insertions(+), 9 deletions(-) create mode 100644 contrib/pg_trgm/pg_trgm--1.6--1.7.sql diff --git a/contrib/pg_trgm/Makefile b/contrib/pg_trgm/Makefile index c1756993ec7..b9b8903169c 100644 --- a/contrib/pg_trgm/Makefile +++ b/contrib/pg_trgm/Makefile @@ -9,9 +9,9 @@ OBJS = \ trgm_regexp.o EXTENSION = pg_trgm -DATA = pg_trgm--1.5--1.6.sql pg_trgm--1.4--1.5.sql pg_trgm--1.3--1.4.sql \ - pg_trgm--1.3.sql pg_trgm--1.2--1.3.sql pg_trgm--1.1--1.2.sql \ - pg_trgm--1.0--1.1.sql +DATA = pg_trgm--1.6--1.7.sql pg_trgm--1.5--1.6.sql pg_trgm--1.4--1.5.sql \ + pg_trgm--1.3--1.4.sql pg_trgm--1.3.sql pg_trgm--1.2--1.3.sql \ + pg_trgm--1.1--1.2.sql pg_trgm--1.0--1.1.sql PGFILEDESC = "pg_trgm - trigram matching" REGRESS = pg_trgm pg_utf8_trgm pg_word_trgm pg_strict_word_trgm diff --git a/contrib/pg_trgm/pg_trgm--1.6--1.7.sql b/contrib/pg_trgm/pg_trgm--1.6--1.7.sql new file mode 100644 index 00000000000..3ef33a512ec --- /dev/null +++ b/contrib/pg_trgm/pg_trgm--1.6--1.7.sql @@ -0,0 +1,19 @@ +/* contrib/pg_trgm/pg_trgm--1.6--1.7.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION pg_trgm UPDATE TO '1.7'" to load this file. \quit + +-- The planner's generic, selectivity-based cost model for GiST index scans +-- has no way to account for gtrgm_consistent()'s containment-style check +-- for '=' being a false positive at signature-tree nodes regardless of how +-- selective the query value actually is (short strings, with few +-- trigrams, are especially prone to this). That can make the planner +-- choose a gist_trgm_ops index over a much cheaper btree index for a +-- plain equality query, sometimes by orders of magnitude in actual +-- execution time. gin_trgm_ops does not have this problem: GIN's cost +-- estimator was fixed to use real per-key statistics in commit +-- cd9479af2af ("Improve GIN cost estimation"). Until GiST's cost +-- estimator gets an analogous fix, stop offering '=' via gist_trgm_ops; +-- gin_trgm_ops is unaffected and keeps supporting it. +ALTER OPERATOR FAMILY gist_trgm_ops USING gist +DROP OPERATOR 11 (text, text); diff --git a/contrib/pg_trgm/pg_trgm.control b/contrib/pg_trgm/pg_trgm.control index 1d6a9ddf259..6e3ee43c510 100644 --- a/contrib/pg_trgm/pg_trgm.control +++ b/contrib/pg_trgm/pg_trgm.control @@ -1,6 +1,6 @@ # pg_trgm extension comment = 'text similarity measurement and index searching based on trigrams' -default_version = '1.6' +default_version = '1.7' module_pathname = '$libdir/pg_trgm' relocatable = true trusted = true diff --git a/doc/src/sgml/pgtrgm.sgml b/doc/src/sgml/pgtrgm.sgml index 07bfcac9319..57e76d27862 100644 --- a/doc/src/sgml/pgtrgm.sgml +++ b/doc/src/sgml/pgtrgm.sgml @@ -416,12 +416,16 @@ the purpose of very fast similarity searches. These index types support the above-described similarity operators, and additionally support trigram-based index searches for LIKE, ILIKE, - ~, ~* and = queries. - The similarity comparisons are case-insensitive in a default build of - pg_trgm. + ~ and ~* queries. The GIN operator + class additionally supports = queries; the GiST + operator class does not, because GiST's cost estimator has no way to + recognize that this can require visiting most of the index regardless of + how selective the query value is, which can make the planner choose it + over a much cheaper B-tree index. The similarity comparisons are + case-insensitive in a default build of pg_trgm. Inequality operators are not supported. - Note that those indexes may not be as efficient as regular B-tree indexes - for equality operator. + Note that even the GIN index may not be as efficient as a regular B-tree + index for the equality operator. -- 2.43.0