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 1ioUCi-0006wT-JI for pgsql-hackers@arkaria.postgresql.org; Mon, 06 Jan 2020 15:22:04 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1ioUCh-0006AC-4l for pgsql-hackers@arkaria.postgresql.org; Mon, 06 Jan 2020 15:22:03 +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 1ioUCg-0006A2-KH for pgsql-hackers@lists.postgresql.org; Mon, 06 Jan 2020 15:22:02 +0000 Received: from mail-wm1-x343.google.com ([2a00:1450:4864:20::343]) by makus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1ioUCd-0006zp-Aw for pgsql-hackers@lists.postgresql.org; Mon, 06 Jan 2020 15:22:01 +0000 Received: by mail-wm1-x343.google.com with SMTP id m24so15337970wmc.3 for ; Mon, 06 Jan 2020 07:21:59 -0800 (PST) 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:content-transfer-encoding:in-reply-to; bh=zar2nAIKIdN6sfHPJXzczsat651EEDJIUp2oQU6yp0Y=; b=lcTFPVYnAsg2AW8EZQpr9lMSsRJJ9D090+ZfR7g12v7sZBwZ9ZPnVUD1r8GjCABm5S YhXj9yGnIcjkYjj8D3uIMSzp7mpzwG8viPOBJNz+VJV0H7e7hKX9H/5n9vXhiYIyBRbI OAZ9TECbnLoyA6q8CWz8zzUjaIV6VoaAkoWIOBmIWHeMD2gwNfWXObfJymCIDriJh1uU 3oN/AZRfLa1Q/ePpXv9lC63j+MIBSYifYumFt+Lr2IiuBtf/7l64jgFH4tWU49GdNbye ZRuWBFYdI7ZH8WRXW32+3xjWSZBMqsNxycjKvq3g0a8Lc74mQyj/29zPjDB844fnAqF7 mh5A== 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:content-transfer-encoding :in-reply-to; bh=zar2nAIKIdN6sfHPJXzczsat651EEDJIUp2oQU6yp0Y=; b=hdGDWxHAijcDR/IE5hfi9Xhi5pfwc19FZpEnfHx7DthWRsJC1QlvbFLYhNhIFF20WG 3QR+/N4CCSskw9K1pDblJWTbZcMgWaJog0uCK4mT4EWLyCTI3bOx5kWDvG+tNG3orl22 nbJubtfE3nd2bDpMgN+sC0vT1yG2xHt4237oVxZv15U424UO9eAr9/mVKPDHvfl4QidP W8cuR1/Nc/HtVrcBfbXIohE1LWkmvxgsE5as8dGTvIJpqltf2GGR5a72GHmROfgtAKwk ixOcEdJXGQVolY91IBcCT01APS0rJVuBlLyN/LYlNmYaJ6uNpkFJjGcI2PRg1paXE8Me 0wTg== X-Gm-Message-State: APjAAAVT2MN6EQiyERYnP8blKM9C00WbtYymgEzvohcNYHF3EwfArNBV qeiH8pDLU58tAx8jsICgStICNg== X-Google-Smtp-Source: APXvYqxzqm8TmjYiZ52g2NIm62daCIH5AceUkZiEaWC9mZGIDXZ05uyxwBnlqZrzlivkroYDLb89cw== X-Received: by 2002:a05:600c:2207:: with SMTP id z7mr33901857wml.138.1578324117403; Mon, 06 Jan 2020 07:21:57 -0800 (PST) Received: from localhost (ip-86-49-253-92.net.upcbroadband.cz. [86.49.253.92]) by smtp.gmail.com with ESMTPSA id l17sm70578802wro.77.2020.01.06.07.21.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 06 Jan 2020 07:21:56 -0800 (PST) Date: Mon, 6 Jan 2020 16:21:55 +0100 From: Tomas Vondra To: Nikita Glukhov Cc: Alexander Korotkov , PostgreSQL Hackers , Tom Lane , Julien Rouhaud , Thomas Munro , Marc Cousin Subject: Re: Avoid full GIN index scan when possible Message-ID: <20200106152155.uuungi2p776p5lbk@development> References: <17590.1564685940@sss.pgh.pa.us> <19189.1564687723@sss.pgh.pa.us> <19438.1565209940@sss.pgh.pa.us> MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1; format=flowed Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk On Fri, Dec 27, 2019 at 04:36:14AM +0300, Nikita Glukhov wrote: >On 26.12.2019 4:59, Alexander Korotkov wrote: >> >> I've tried to add patch #4 to comparison, but I've catch assertion >>failure. >> >>TRAP: FailedAssertion("key->includeNonMatching", File: "ginget.c", >>Line: 1340) >There simply should be inverted condition in the assertion: >Assert(!key->includeNonMatching); > >I have looked at v9 patch, and here is my review: > >1. I agree with NULL-flag handling simplifications in ginNewScanKey(), >ginScanKeyAddHiddenEntry() extraction. > >2. I also agree that usage of nrequired/nadditional in keyGetItem() is a more >natural solution to implement exclusion keys than my previous attempt of doing >that in scanGetKey(). > >But there are some questions: > >Can we avoid referencing excludeOnly flag keyGetItem() by replacing these >references with !nrequired? > >Maybe it would be better to move the whole block of keyGetItem() code >starting from the first loop over required keys and ending before the loop over >additional keys inside 'if (key->nrequired) { ... }'? > >Can we avoid introducing excludeOnly flag by reusing searchMode and/or by >moving the initialization of nrequired/nadditional into ginNewScanKey()? > > >3. The following two times repeated NULL-filtering check looks too complicated >and needs to be refactored somehow: > >- res = key->triConsistentFn(key); >+ if (key->excludeOnly && >+ key->nuserentries < key->nentries && >+ key->scanEntry[key->nuserentries]->queryCategory == GIN_CAT_NULL_KEY && >+ key->entryRes[key->nuserentries] == GIN_TRUE) >+ res = GIN_FALSE; >+ else >+ res = key->triConsistentFn(key); > >For example, a special consistentFn() can be introduced for such NOT_NULL >scankeys. Or even a hidden separate one-entry scankey with a trivial >consistentFn() can be added instead of adding hidden entry. > > >4. forcedRecheck flag that was previously used for discarded empty ALL scankeys >is removed now. 0-entry exclusion keys can appear instead, and their >consistentFn() simply returns constant value. Could this lead to tangible >overhead in some cases (in comparison to forcedRecheck flag)? > > >5. A hidden GIN_CAT_EMPTY_QUERY is added only for the first empty ALL-scankey, >NULLs in other columns are filtered out with GIN_CAT_NULL_KEY. This looks like >asymmetric, and it leads to accelerations is some cases and slowdowns in others >(depending on NULL fractions and their correlations in columns). > >The following test shows a significant performance regression of v9: > >insert into t select array[i], NULL, NULL from generate_series(1, 1000000) i; > > | Query time, ms > WHERE condition | master | v8 | v9 >---------------------------------------+--------+--------+--------- > a @> '{}' | 224 | 213 | 212 > a @> '{}' and b @> '{}' | 52 | 57 | 255 > a @> '{}' and b @> '{}' and c @> '{}' | 51 | 58 | 290 > > >In the older version of the patch I tried to do the similar things (initialize >only one NOT_NULL entry for the first column), but refused to do this in v8. > >So, to avoid slowdowns relative to master, I can offer simply to add >GIN_CAT_EMPTY_QUERY entry for each column with empty ALL-keys if there are >no normal keys. > Yeah, I can confirm those results, although on my system the timings are a bit different (I haven't tested v8): | Query time, ms WHERE condition | master | v9 ---------------------------------------+--------+--------- a @> '{}' | 610 | 589 a @> '{}' and b @> '{}' | 185 | 665 a @> '{}' and b @> '{}' and c @> '{}' | 185 | 741 So that's something we probably need to address, perhaps by using the GIN_CAT_EMPTY_QUERY entries as proposed. I've also tested this on a database storing mailing lists archives with a trigram index, and in that case the performance with short values gets much better. The "messages" table has two text fields with a GIN trigram index - subject and body, and querying them with short/long values works like this: WHERE | master | v9 -------------------------------------------------------------- subject LIKE '%aa%' AND body LIKE '%xx%' | 4943 | 4052 subject LIKE '%aaa%' AND body LIKE '%xx%' | 10 | 10 subject LIKE '%aa%' AND body LIKE '%xxx%' | 380 | 13 subject LIKE '%aaa%' AND BODY LIKE '%xxx%' | 2 | 2 which seems fairly nice. I've done tests with individual columns, and that seems to be working fine too. regards -- Tomas Vondra http://www.2ndQuadrant.com PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services