Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1hhAXw-0001PB-5X for pgsql-hackers@arkaria.postgresql.org; Sat, 29 Jun 2019 10:25:28 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1hhAXu-0006jU-TD for pgsql-hackers@arkaria.postgresql.org; Sat, 29 Jun 2019 10:25:26 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1hhAXu-0006hb-Bj for pgsql-hackers@lists.postgresql.org; Sat, 29 Jun 2019 10:25:26 +0000 Received: from mail-wm1-x343.google.com ([2a00:1450:4864:20::343]) by makus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1hhAXm-0004KU-Tb for pgsql-hackers@lists.postgresql.org; Sat, 29 Jun 2019 10:25:24 +0000 Received: by mail-wm1-x343.google.com with SMTP id x15so11394226wmj.3 for ; Sat, 29 Jun 2019 03:25:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=2ndquadrant-com.20150623.gappssmtp.com; s=20150623; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=iTa8phtGznWHDznF9sJAP9Sa1Y5Ig85xmYf3tl/St5I=; b=o94eMcgkPX3gnqjMI7mRWCNTcbdZ9PQu7dPoY0CFXzjRBGZtY1zdO3sKpQlun5zflD /LmCnfSG3gupLrewCsoS/Z+CvNrdZxEo7et53dAV7apd0u67oE2KkubOCgBQzLotuWos FVl1tmP2xLp6Y5n3WUGMMC11fx9bgdRd14Wcf/+zCxBg+HXKda2njq9WLqeC2L++X3Zb dqx8IBWDe4NY2iL1U3l81r4KuXn+vehQ6bzssjlP4ntnu8b6y6fGzGCs/oe1sy+K0cR2 VETov9Dejb61EOBroeZUmKdfrxwgKpAmRzUb3rxP7wmcCfmT/qAqvQ86ZOrVQPau2e8Q +EDQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=iTa8phtGznWHDznF9sJAP9Sa1Y5Ig85xmYf3tl/St5I=; b=B4ysDtwGFpgIuL6tI9+EyTWfuGcdKnQjj+b3+PHRIO+htCCuFcuQ77SIPbwY8wRS/I 9GQFtgkbvX6ylR+biUUBdtmo2noUhLCz/Ee2qpRRg3hqu1CiBFV3NTtlRDtTqlhAXPTF 0Mwm5Pnl61e8ENDT+LxrSyHRnKoL2mr2QzBMtAzvyxjwm5TQvcJXC9mYEq7Do54Ugwve Mj88NTcyF345PvW4bD8zHIQYl9vxKafyZDEPKxR/gX6kYgaxevRSkmvkW8+bsXdmWaNL oWMz1SbpjIoUcj66ZDhpdk2dkEngZjllwObC6GLgJ8kD+yfBlDDJ5/HiYHzDR2I85mfl g1Qw== X-Gm-Message-State: APjAAAWMzHXASb1jA4PDVm3zmOxHdW56TymbOJ+7EbIrYuKuAc6Ps7Re TZIYdgbQMoKi+q7THTWvOj4IEA== X-Google-Smtp-Source: APXvYqwW3rNuJng+upDAH5c2dLk+dkEB3OMcQd1rww4osVPOhxrRvzoqFu8grN1p3gvYhFG/SHrt+g== X-Received: by 2002:a1c:a1c1:: with SMTP id k184mr10952190wme.81.1561803917360; Sat, 29 Jun 2019 03:25:17 -0700 (PDT) Received: from localhost (ip-86-49-253-160.net.upcbroadband.cz. [86.49.253.160]) by smtp.gmail.com with ESMTPSA id f13sm4290157wrt.89.2019.06.29.03.25.16 (version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256); Sat, 29 Jun 2019 03:25:16 -0700 (PDT) Date: Sat, 29 Jun 2019 12:25:14 +0200 From: Tomas Vondra To: Julien Rouhaud Cc: Nikita Glukhov , PostgreSQL Hackers , Tom Lane , Marc Cousin Subject: Re: Avoid full GIN index scan when possible Message-ID: <20190629102514.ucfzglxu7ccjsbjr@development> References: <20190628161051.szk2kxmue6yjdmra@development> <4547.1561748599@sss.pgh.pa.us> <20190628195401.frwhcga76rrytbc4@development> <7773.1561752983@sss.pgh.pa.us> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Disposition: inline In-Reply-To: User-Agent: NeoMutt/20180716-1444-295967 List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk On Sat, Jun 29, 2019 at 11:10:03AM +0200, Julien Rouhaud wrote: >On Sat, Jun 29, 2019 at 12:51 AM Nikita Glukhov > wrote:> >> On 29.06.2019 1:23, Julien Rouhaud wrote: >> >> But that kinda resembles stuff we already have - selectivity/cost. So >> why shouldn't this be considered as part of costing? >> >> Yeah, I'm not entirely convinced that we need anything new here. >> The cost estimate function can detect such situations, and so can >> the index AM at scan start --- for example, btree checks for >> contradictory quals at scan start. There's a certain amount of >> duplicative effort involved there perhaps, but you also have to >> keep in mind that we don't know the values of run-time-determined >> comparison values until scan start. So if you want certainty rather >> than just a cost estimate, you may have to do these sorts of checks >> at scan start. >> >> Ah, I didn't know about _bt_preprocess_keys(). I'm not familiar with >> this code, so please bear with me. IIUC the idea would be to add >> additional logic in gingetbitmap() / ginNewScanKey() to drop some >> quals at runtime. But that would mean that additional logic would >> also be required in BitmapHeapScan, or that all the returned bitmap >> should be artificially marked as lossy to enforce a recheck? >> >> We have a similar solution for this problem. The idea is to avoid full index >> scan inside GIN itself when we have some GIN entries, and forcibly recheck >> all tuples if triconsistent() returns GIN_MAYBE for the keys that emitted no >> GIN entries. > >Thanks for looking at it. That's I think a way better approach. > >> The attached patch in its current shape contain at least two ugly places: >> >> 1. We still need to initialize empty scan key to call triconsistent(), but >> then we have to remove it from the list of scan keys. Simple refactoring >> of ginFillScanKey() can be helpful here. >> >> 2. We need to replace GIN_SEARCH_MODE_EVERYTHING with GIN_SEARCH_MODE_ALL >> if there are no GIN entries and some key requested GIN_SEARCH_MODE_ALL >> because we need to skip NULLs in GIN_SEARCH_MODE_ALL. Simplest example here >> is "array @> '{}'": triconsistent() returns GIN_TRUE, recheck is not forced, >> and GIN_SEARCH_MODE_EVERYTHING returns NULLs that are not rechecked. Maybe >> it would be better to introduce new GIN_SEARCH_MODE_EVERYTHING_NON_NULL. > >Also > >+ if (searchMode == GIN_SEARCH_MODE_ALL && nQueryValues <= 0) >+ { >+ /* >+ * Don't emit ALL key with no entries, check only whether >+ * unconditional recheck is needed. >+ */ >+ GinScanKey key = &so->keys[--so->nkeys]; >+ >+ hasSearchAllMode = true; >+ so->forcedRecheck = key->triConsistentFn(key) != GIN_TRUE; >+ } > >Shouldn't you make sure that the forcedRecheck flag can't reset? > >> -- patched >> EXPLAIN ANALYZE SELECT * FROM test WHERE t LIKE '%1234%' AND t LIKE '%1%'; >> QUERY PLAN >> ----------------------------------------------------------------------------------------------------------------------- >> Bitmap Heap Scan on test (cost=20.43..176.79 rows=42 width=6) (actual time=0.287..0.424 rows=300 loops=1) >> Recheck Cond: ((t ~~ '%1234%'::text) AND (t ~~ '%1%'::text)) >> Rows Removed by Index Recheck: 2 >> Heap Blocks: exact=114 >> -> Bitmap Index Scan on test_t_idx (cost=0.00..20.42 rows=42 width=0) (actual time=0.271..0.271 rows=302 loops=1) >> Index Cond: ((t ~~ '%1234%'::text) AND (t ~~ '%1%'::text)) >> Planning Time: 0.080 ms >> Execution Time: 0.450 ms >> (8 rows) > >One thing that's bothering me is that the explain implies that the >LIKE '%i% was part of the index scan, while in reality it wasn't. One >of the reason why I tried to modify the qual while generating the path >was to have the explain be clearer about what is really done. Yeah, I think that's a bit annoying - it'd be nice to make it clear which quals were actually used to scan the index. It some cases it may not be possible (e.g. in cases when the decision is done at runtime, not while planning the query), but it'd be nice to show it when possible. A related issue is that during costing is too late to modify cardinality estimates, so the 'Bitmap Index Scan' will be expected to return fewer rows than it actually returns (after ignoring the full-scan quals). Ignoring redundant quals (the way btree does it at execution) does not have such consequence, of course. Which may be an issue, because we essentially want to modify the list of quals to minimize the cost of bitmap index scan + recheck during bitmap heap scan OTOH it's not a huge issue, because it won't affect the rest of the plan (because that uses the bitmap heap scan estimates, and those are not affected by this). regards -- Tomas Vondra http://www.2ndQuadrant.com PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services