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 1kLb0n-0006Qk-Rm for pgsql-hackers@arkaria.postgresql.org; Thu, 24 Sep 2020 23:50:54 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1kLb0m-0004Rc-Q9 for pgsql-hackers@arkaria.postgresql.org; Thu, 24 Sep 2020 23:50:52 +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 1kLb0m-0004RL-B8 for pgsql-hackers@lists.postgresql.org; Thu, 24 Sep 2020 23:50:52 +0000 Received: from mail-ej1-x644.google.com ([2a00:1450:4864:20::644]) by makus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1kLb0j-00030y-Kl for pgsql-hackers@postgresql.org; Thu, 24 Sep 2020 23:50:51 +0000 Received: by mail-ej1-x644.google.com with SMTP id z23so1090974ejr.13 for ; Thu, 24 Sep 2020 16:50:49 -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; bh=sfclXQ4hCzjmQLDWzeKgV1SHK+W2h8w2J7LFq74KEMs=; b=vVQBcyt+ZstK7giq+BkAXOGEXbl7SMBcj7U3vGfNk3eWNAXVtSiJxpFOftVpumgn5/ 3iqd+JxXODHy0Qi/JcfSasbAuC4aFXerT0yF2hvatvyPQqFn/XYV4m+u1iv3dtsdlfK9 02l8cnW7PVZr6+Mk/AwhQffNGVnQjzREayAFny8A9SrUkPboP6SSl8kQ0IBSd13/+L56 JNOXzvUuiGaIXoUMPt+5vtuU0dMwlZY8kywr5VQGGEZIos8N+3LanVRrYPtvQ8Q3UuN4 4FuZ4yoDou+lTAJdq9gamM/eSVhpz+oqMbkZaR9zHLE94UbAv/ZmN2TLFK80cyALeOG1 GcnA== 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; bh=sfclXQ4hCzjmQLDWzeKgV1SHK+W2h8w2J7LFq74KEMs=; b=NLZDM1hJkbK+fLdKEMbgB8EgxXT5RiQfqdCweOzm2iBytlXuW3tv9d5EjzQgfMt0rF 7440qxh7qJz+KPi/Zap/9YJ9L5F0sZ54J+C3AYp+hmiI7ZALtGwM4KFseZ2NOlfzlG/M BlwO67Ngn6VDdU1+3st5rGU7us9J3tXU2R1VcxhztIWzYrfPfdOxV04Em9JlVNEhmHLW T+RecNpQm5hRBpNFUgV8WAIoZamAfhh01PNCReAE+6i/cOdseCJ1e46Lo+M+/mJzs94b LkiMRPjRSSFrFnBVx+pKp22TVVMBM9hE3yCLDNYPn+T3a+D7Gd/oV+oadf6GMQJ0W/7Q 4W4A== X-Gm-Message-State: AOAM532i6HKHaBuMMg50nlUjykbfNIc4NDm6hjRoCmkUgFU/e5F3nOKn gJOV/cKm3IjfGrStXmlpiNFSuw== X-Google-Smtp-Source: ABdhPJzLHengKNLokZnB2aMpJ7t4jLez31gUhOCKvLgthAZK4/BeCLmIMR/lbMSlOtAnCxAoEXZrDg== X-Received: by 2002:a17:906:2dc1:: with SMTP id h1mr96648eji.436.1600991448134; Thu, 24 Sep 2020 16:50:48 -0700 (PDT) Received: from localhost (ip-86-49-245-76.net.upcbroadband.cz. [86.49.245.76]) by smtp.gmail.com with ESMTPSA id um10sm661298ejb.8.2020.09.24.16.50.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 24 Sep 2020 16:50:47 -0700 (PDT) Date: Fri, 25 Sep 2020 01:50:45 +0200 From: Tomas Vondra To: John Naylor Cc: Alvaro Herrera , pgsql-hackers Subject: Re: WIP: BRIN multi-range indexes Message-ID: <20200924235045.bgxsilvf7askukph@development> References: <20200917163426.zzyi62zshwemkfhx@development> <20200918114014.sz5a3nwt7zont4rz@development> <20200918222702.omsieaphfj3ctqg3@development> <20200921195607.gt6xbia7v55bhuwq@development> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Disposition: inline In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk On Thu, Sep 24, 2020 at 05:18:03PM -0400, John Naylor wrote: >On Mon, Sep 21, 2020 at 3:56 PM Tomas Vondra > wrote: >> >> On Mon, Sep 21, 2020 at 01:42:34PM -0400, John Naylor wrote: > >> >While playing around with the numbers I had an epiphany: At the >> >defaults, the filter already takes up ~4.3kB, over half the page. >> >There is no room for another tuple, so if we're only indexing one >> >column, we might as well take up the whole page. >> >> Hmm, yeah. I may be wrong but IIRC indexes don't support external >> storage but compression is still allowed. So even if those defaults are >> a bit higher than needed that should make the bloom filters a bit more >> compressible, and thus fit multiple BRIN tuples on a single page. > >> Not sure about how much we want to rely on these optimizations, though, >> considering multi-column indexes kinda break this. > >Yeah. Okay, then it sounds like we should go in the other direction, >as the block comment at the top of brin_bloom.c implies. Indexes with >multiple bloom-indexed columns already don't fit in one 8kB page, so I >think every documented example should have a much lower >pages_per_range. Using 32 pages per range with max tuples gives n = >928. With default p, that's about 1.1 kB per brin tuple, so one brin >page can index 224 pages, much more than with the default 128. > >Hmm, how ugly would it be to change the default range size depending >on the opclass? > Not sure. What would happen for multi-column BRIN indexes with different opclasses? >If indexes don't support external storage, that sounds like a pain to >add. Also, with very small fpr, you can easily get into many megabytes >of filter space, which kind of defeats the purpose of brin in the >first place. > True. >There is already this item from the brin readme: > >* Different-size page ranges? > In the current design, each "index entry" in a BRIN index covers the same > number of pages. There's no hard reason for this; it might make sense to > allow the index to self-tune so that some index entries cover smaller page > ranges, if this allows the summary values to be more compact. This >would incur > larger BRIN overhead for the index itself, but might allow better pruning of > page ranges during scan. In the limit of one index tuple per page, the index > itself would occupy too much space, even though we would be able to skip > reading the most heap pages, because the summary values are tight; in the > opposite limit of a single tuple that summarizes the whole table, we wouldn't > be able to prune anything even though the index is very small. This can > probably be made to work by using the range map as an index in itself. > >This sounds like a lot of work, but would be robust. > Yeah. I think it's a fairly independent / orthogonal project. >Anyway, given that this is a general problem and not specific to the >prime partition algorithm, I'll leave that out of the attached patch, >named as a .txt to avoid confusing the cfbot. > >> >We could also generate the primes via a sieve instead, which is really >> >fast (and more code). That would be more robust, but that would require >> >the filter to store the actual primes used, so 20 more bytes at max k = >> >10. We could hard-code space for that, or to keep from hard-coding >> >maximum k and thus lowest possible false positive rate, we'd need more >> >bookkeeping. >> > >> >> I don't think the efficiency of this code matters too much - it's only >> used once when creating the index, so the simpler the better. Certainly >> for now, while testing the partitioning approach. > >To check my understanding, isn't bloom_init() called for every tuple? >Agreed on simplicity so done this way. > No, it's only called for the first non-NULL value in the page range (unless I made a boo boo when writing that code). >> >So, with the partition approach, we'd likely have to set in stone >> >either max nbits, or min target false positive rate. The latter option >> >seems more principled, not only for the block size, but also since the >> >target fp rate is already fixed by the reloption, and as I've >> >demonstrated, we can often go above and beyond the reloption even >> >without changing k. >> > >> >> That seems like a rather annoying limitation, TBH. > >I don't think the latter is that bad. I've capped k at 10 for >demonstration's sake.: > >(928 is from using 32 pages per range) > >n k m p >928 7 8895 0.01 >928 10 13343 0.001 (lowest p supported in patch set) >928 13 17790 0.0001 >928 10 18280 0.0001 (still works with lower k, needs higher m) >928 10 17790 0.00012 (even keeping m from row #3, capping k doesn't >degrade p much) > >Also, k seems pretty robust against small changes as long as m isn't >artificially constrained and as long as p is small. > >So I *think* it's okay to cap k at 10 or 12, and not bother with >adjusting m, which worsens space issues. As I found before, lowering k >raises target fpr, but seems more robust to overshooting ndistinct. In >any case, we only need k * 2 bytes to store the partition lengths. > >The only way I see to avoid any limitation is to make the array of >primes variable length, which could be done by putting the filter >offset calculation into a macro. But having two variable-length arrays >seems messy. > Hmmm. I wonder how would these limitations impact the conclusions from the one-hashing paper? Or was this just for the sake of a demonstration? I'd suggest we just do the simplest thing possible (be it a hard-coded table of primes or a sieve) and then evaluate if we need to do something more sophisticated. >> >Hmm, I'm not sure I understand you. I can see not caring to trim wasted >> >bits, but we can't set/read off the end of the filter. If we don't >> >wrap, we could just skip reading/writing that bit. So a tiny portion of >> >access would be at k - 1. The paper is not clear on what to do here, >> >but they are explicit in minimizing the absolute value, which could go >> >on either side. >> > >> >> What I meant is that is that the paper says this: >> >> Given a planned overall length mp for a Bloom filter, we usually >> cannot get k prime numbers to make their sum mf to be exactly mp. As >> long as the difference between mp and mf is small enough, it neither >> causes any trouble for the software implementation nor noticeably >> shifts the false positive ratio. >> >> Which I think means we can pick mp, generate k primes with sum mf close >> to mp, and just use that with mf bits. > >Oh, I see. When I said "trim" I meant exactly that (when mf < mp). >Yeah, we can bump it up as well for the other case. I've done it that >way. > OK >> >+ add_local_real_reloption(relopts, "false_positive_rate", + "desired >> >false-positive rate for the bloom filters", + >> >BLOOM_DEFAULT_FALSE_POSITIVE_RATE, + 0.001, 1.0, offsetof(BloomOptions, >> >falsePositiveRate)); >> > >> >When I set fp to 1.0, the reloption code is okay with that, but then >> >later the assertion gets triggered. >> > >> >> Hmm, yeah. I wonder what to do about that, considering indexes with fp >> 1.0 are essentially useless. > >Not just useless -- they're degenerate. When p = 1.0, m = k = 0 -- We >cannot accept this value from the user. Looking up thread, 0.1 was >suggested as a limit. That might be a good starting point. > Makes sense, I'll fix it that way. >This is interesting work! Having gone this far, I'm going to put more >attention to the multi-minmax patch and actually start performance >testing. > Cool, thanks! I'll take a look at your one-hashing patch tomorrow. regards -- Tomas Vondra http://www.2ndQuadrant.com PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services