Received: from malur.postgresql.org ([2a02:16a8:dc51::56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA384:256) (Exim 4.89) (envelope-from ) id 1fz7ax-0002kj-R5 for pgsql-hackers@arkaria.postgresql.org; Sun, 09 Sep 2018 21:50:16 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1fz7av-0003eY-0a for pgsql-hackers@arkaria.postgresql.org; Sun, 09 Sep 2018 21:50:13 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA384:256) (Exim 4.89) (envelope-from ) id 1fz7au-0003eJ-J5 for pgsql-hackers@lists.postgresql.org; Sun, 09 Sep 2018 21:50:12 +0000 Received: from mail-wm0-x244.google.com ([2a00:1450:400c:c09::244]) by magus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1fz7ap-00033C-7u for pgsql-hackers@postgresql.org; Sun, 09 Sep 2018 21:50:11 +0000 Received: by mail-wm0-x244.google.com with SMTP id b19-v6so19564418wme.3 for ; Sun, 09 Sep 2018 14:50:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=2ndquadrant-com.20150623.gappssmtp.com; s=20150623; h=subject:to:cc:references:from:message-id:date:user-agent :mime-version:in-reply-to:content-language:content-transfer-encoding; bh=1i7xjhvxBRUmQrI14hFixSX1fx8EVeMLTwF8wYlrf+U=; b=kW7KMaTqnLnuIYydTWdilf62M3AAUKVHJdjssoOTB4A+Q0z2jJ0h2WERAWJbkB/QHx mMFn22vvagmVWlTi1xxTbdMxC5Tz7QeyniKPplSmqY5b/TwaxlxOwxlW57XrUz8Ucg9I yKcU0EfdZxF4+kgrGyTG0MwDAKcbepCVCxEMNMdJVRstJLzgAm1nPmQhu1C5LtfmeCjM nwL0q12RcUzavdTa5oZVuxS/calYAlD6d0Uo7QnS2pxm7JydJQP+8zQu+/flB8eC2y24 I1qYyIK1pnTQN/U0Pz8VjOQo40xL85BmPCRnu4EeNpqawQ6hVIKymXBEPIKWhsY+TQoE ih9w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:cc:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=1i7xjhvxBRUmQrI14hFixSX1fx8EVeMLTwF8wYlrf+U=; b=IgDgKAqUO5QMW/gTPe5Cr0xFCb2hIiyHQ5V269OtKUdAcPfv6Qd7fwQVGPd/1YxbC8 vSNId73mCwaHBCQtm67Vpa5WIotAt/JLV1ebKwU3V6JrF0YXMNsmC4BaLv5Wj9Q//bsK 08fFifKWo08XGbx3qc6+kEUJfszWqf8DcP1ZHYedsw5vMR1HBWQYrPU/YU8ycmSGW5dB 5sNmaV3HpuuMMwVsKDeKbtnHwAyxr64UycrVdkj8Cq6CWKVoLM6d8D+c0MTZm6MdkfCg 3uNOwroed+XLQFibrnEHOlndjPmemxLbVE9XLW3iY1FklpVu0OrOHkE7lQ/Q0mdGHoxJ Mp/Q== X-Gm-Message-State: APzg51Ctynww/bQEqg4zb+ZGkUtHKAGA6yJNYbcYqFkwSz6W8DXGvBMj pmGnATqj0SYqbFKd9N/7tTjrnnU5zxdMnAw2PdCeH2F1C4f+9Pcq1JdpnvgfEZkRA4x8QZjRL5w t6PZ/O9AxXJ3CUJ1gkDcQt3zAzPf8Ayl3FBMxP431pGhOBjRDLo64cj3yAOVAjcIw7dpvpUWEAh BGls1ZXUHJXmg= X-Google-Smtp-Source: ANB0VdYoaVIw7Xg6FhKScSiHYHj1KvMo2cA+KdvpOZqPSdBJV/GiGx2rS2tNA/hYxFNw+GavbtMkRQ== X-Received: by 2002:a1c:1f50:: with SMTP id f77-v6mr12068742wmf.52.1536529804444; Sun, 09 Sep 2018 14:50:04 -0700 (PDT) Received: from [10.137.2.19] (ip-86-49-246-121.net.upcbroadband.cz. [86.49.246.121]) by smtp.gmail.com with ESMTPSA id e14-v6sm9908428wrv.44.2018.09.09.14.50.03 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 09 Sep 2018 14:50:03 -0700 (PDT) Subject: Re: [HACKERS] PATCH: multivariate histograms and MCV lists To: Dean Rasheed Cc: Bruce Momjian , Alvaro Herrera , Andres Freund , Thomas Munro , Mark Dilger , Adrien Nayrat , Pg Hackers References: <49348328-1a02-7e45-e50f-e1d4d0243c5c@2ndquadrant.com> <4416a567-4452-c5fd-7117-5cc7827b5fad@2ndquadrant.com> <80bc98b2-1c43-1fe8-b316-d447bb68cff2@2ndquadrant.com> <341ca23f-144d-130d-1b45-ddddf581797e@2ndquadrant.com> <8ac8bd94-478d-215d-e6bd-339f1f20a74c@2ndquadrant.com> From: Tomas Vondra Message-ID: Date: Sun, 9 Sep 2018 23:49:59 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.5.2 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk Hi, On 09/04/2018 04:16 PM, Dean Rasheed wrote: > On 3 September 2018 at 00:17, Tomas Vondra wrote: >> Hi, >> >> Attached is an updated version of the patch series, adopting a couple of >> improvements - both for MCV lists and histograms. >> >> >> MCV >> --- >> >> For the MCV list part, I've adopted the approach proposed by Dean, using >> base selectivity and using it to correct the non-MCV part. I agree the >> simplicity of the approach is a nice feature, and it seems to produce >> better estimates. I'm not sure I understand the approach perfectly, but >> I've tried to add comments explaining how it works etc. >> > > Cool. Looking at this afresh after some time away, it still looks like > a reasonable approach, and the test results are encouraging. > > In mcv_clauselist_selectivity(), you raise the following question: > > if (matches[i] != STATS_MATCH_NONE) > { > /* XXX Shouldn't the basesel be outside the if condition? */ > *basesel += mcv->items[i]->base_frequency; > s += mcv->items[i]->frequency; > } > > The reason it needs to be inside the "if" block is that what it's > computing is the base (independent) selectivity of the clauses found > to match the MCV stats, so that then in > statext_clauselist_selectivity() it can be used in the following > computation: > > /* Estimated selectivity of values not covered by MCV matches */ > other_sel = simple_sel - mcv_basesel; > > to give an estimate for the other clauses that aren't covered by the > MCV stats. So I think the code is correct as it stands, but if you > think it isn't clear enough, maybe a comment update is in order. > > The assumption being made is that mcv_basesel will cancel out the part > of simple_sel that is due to clauses matching the MCV stats, so that > we can then just add on the MCV selectivity. Of course that's only an > approximation, and it won't be exact -- partly due to the fact that > simple_sel and mcv_basesel are potentially computed using different > sample rows, and so will differ in the MCV region, and partly because > of second-order effects arising from the way that selectivities are > combined in clauselist_selectivity_simple(). Maybe that's something > that can be improved upon, but it doesn't seem like a bad initial > approximation. > Thanks for the clarification. It's one of the comments I added while reworking the patch, with still a very limited understanding of the approach at that point in time. I'll replace it with a comment explaining the reasoning in the next version. > >> I've also changed how we build the MCV lists, particularly how we decide >> how many / which items store in the MCV list. In the previous version >> I've adopted the same algorithm we use for per-column MCV lists, but in >> certain cases that turned out to be too restrictive. >> >> Consider for example a table with multiple perfectly correlated columns, >> with very few combinations. That is, something like this: >> >> CREATE TABLE t (a int, b int); >> >> INSERT INTO t SELECT mod(i,50), mod(i,50) >> FROM generate_series(1,1e6) s(i); >> >> CREATE STATISTICS s (mcv) ON a,b FROM t; >> >> Now, the data distribution is very simple - uniform, with 50 distinct >> combinations, each representing 2% of data (and the random sample should >> be pretty close to that). >> >> In these cases, analyze_mcv_list decides it does not need any MCV list, >> because the frequency for each value is pretty much 1/ndistinct. For >> single column that's reasonable, but for multiple correlated columns >> it's rather problematic. We might use the same ndistinct approach >> (assuming we have the ndistinct coefficients), but that still does not >> allow us to decide which combinations are "valid" with respect to the >> data. For example we can't decide (1,10) does not appear in the data. >> >> So I'm not entirely sure adopting the same algorithm analyze_mcv_list >> algorithm both for single-column and multi-column stats. It may make >> sense to keep more items in the multi-column case for reasons that are >> not really valid for a single single-column. >> >> For now I've added a trivial condition to simply keep all the groups >> when possible. This probably needs more thought. >> > > Ah, this is a good point. I think I see the problem here. > > analyze_mcv_list() works by keeping those MCV entries that are > statistically significantly more frequent than the selectivity that > would have otherwise been assigned to the values, which is based on > ndistinct and nullfrac. That's not really right for multivariate stats > though, because the selectivity that would be assigned to a > multi-column value if it weren't in the multivariate MCV list is > actually calculated using the product of individual column > selectivities. Fortunately we now calculate this (base_frequency), so > actually I think what's needed is a custom version of > analyze_mcv_list() that keeps MCV entries if the observed frequency is > statistically significantly larger than the base frequency, not the > ndistinct-based frequency. > That's probably a good idea and should be an improvement in some cases. But I think it kinda misses the second part, when a combination is much less common than the simple product of selectivities (i.e. values that are somehow "incompatible"). In the example above, there are only (a,b) combinations where (a == b), so there's nothing like that. But in practice there will be some sort of noise. So you may observe combinations where the actual frequency is much lower than the base frequency. I suppose "significantly larger than the base frequency" would not catch that, so we need to also consider cases where it's significantly lower. I also wonder if we could/should consider the multi-variate ndistinct estimate, somehow. For the univariate case wen use the ndistinct to estimate the average selectivity for non-MCV items. I think it'd be a mistake not to leverage this knowledge (when ndistinct coefficients are available), even if it only helps with simple equality clauses. > It might also be worthwhile doing a little more work to make the > base_frequency values more consistent with the way individual column > selectivities are actually calculated -- currently the patch always > uses the observed single-column frequencies to calculate the base > frequencies, but actually the univariate stats would only do that for > a subset of the single-column values, and the rest would get assigned > a fixed share of the remaining selectivity-space. Factoring that into > the base frequency calculation ought to give a better base frequency > estimate (for use in mcv_clauselist_selectivity() and > statext_clauselist_selectivity()), as well as give a more principled > cutoff threshold for deciding which multivariate MCV values to keep. > It may be possible to reuse some of the existing code for that. > I agree, but I think we can leave this for later. > The initial goal of the base frequency calculation was to replicate > the univariate stats computations, so that it can be used to give the > right correction to be applied to the simple_sel value. If it can also > be used to determine how many MCV entries to keep, that's an added > bonus. > Yep. regards -- Tomas Vondra http://www.2ndQuadrant.com PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services