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 1l1gGj-00050g-O9 for pgsql-hackers@arkaria.postgresql.org; Tue, 19 Jan 2021 01:57:18 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1l1gGi-0005ct-Kc for pgsql-hackers@arkaria.postgresql.org; Tue, 19 Jan 2021 01:57:16 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1l1gGi-0005cm-9d for pgsql-hackers@lists.postgresql.org; Tue, 19 Jan 2021 01:57:16 +0000 Received: from mail-ed1-x535.google.com ([2a00:1450:4864:20::535]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1l1gGf-0008Kp-1A for pgsql-hackers@postgresql.org; Tue, 19 Jan 2021 01:57:15 +0000 Received: by mail-ed1-x535.google.com with SMTP id c6so12552908ede.0 for ; Mon, 18 Jan 2021 17:57:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=enterprisedb-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=gSULQsgRubE59bBkTxM5tOmkI8OxFOVair25NbKlK/A=; b=unV3PE8ezM/LjQgBgdv8PpBga7oINic4odMvRM/7B8qd5GTRk33kPlNPdkzQbSRuN1 8c1R2HXELMtCIUPB0iv+7Nu6a0L0yD1KpZj4C8MvoDK+IwHD5owBca7PZ/HCLa84Ao5Y CKOJy7hQCVcPIqnWMW6+pl9+7lpNYvzyWSC+oIGl2z0xlDDPjfGvHH0ngps0Gb2g3I4m 15y+90wrV3PU877anNkc3g7pEZgRUPADJWtUt5maaOggia4Q67Uac1R2yWBzMO3au4Nt NV3udcyE5EpcSzxRme/JbfvbQanwdV/cLGVwb9nBlDVbOocq3X8WNOojjhqoMmHYwZsy xplA== 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=gSULQsgRubE59bBkTxM5tOmkI8OxFOVair25NbKlK/A=; b=EiRO5btqtugrNsjK1xwO1KX5t0zcf4LOanrK0ye8kF+uXz2swZnTTggGFr1d/MWwFs BP6A8UMC3XvnYyaVVJsKrkHjd/3o7eGYrdqpV1Dm/XeGgOHLlTPhdLLQF3dB3jjR+wBh Jd5Q3xzeA8XfxqBz91WClYJ1j0VdZkMfd5+vt3+wQBkEkDyIgt22XvqPVaBSAWnGDFyM Gr/iiQEXGl3DEUrHC1uz7J16N0mggvSmUmyGK/jqFmwNRsOy1gEG81sl+2AsO7Hj6NXM aNGhmVdRIu/IZXOaVQ2+QN9cFHLU1aePIxLny9PhtEgE/UDIhqBdrAnOLCQiyDAa9oum 25mg== X-Gm-Message-State: AOAM532HmSgSqrsTK7Ow6b08nQrGLhXwPRvZ3RDU8/ZreQJpJGQ8Nw+i EP2kUQqI8bvTxC9R2IA3kIOXCbS5cjwbH/e8aqnYdtCyJmgYeDlA6RUQloJdCnQNlU1eI9NNb9Q x1UuXWTQAZiXitU2A97JbupZZ/SmP5wsdbANBTV8ynmQn+a3L++/2dkWML0AWw1oNiC58JS6yzS US1ZG5oR16ljevz9cExuCBuyfpplKpXbbaJwmfzKAc1EmLdNsunS7/TMbD4szMu9ODzBziUYKvN AkWZ2ZbzGNHQpQNYipdeBB+ACKWI65t2sTzrONr X-Google-Smtp-Source: ABdhPJyP/zaC6mczEgoI/M+zNFe0qDgseju0A0WvzWtukodxj0eVT8xMROU5fO+SCxXEnVGbHjCvGw== X-Received: by 2002:a50:b746:: with SMTP id g64mr1637956ede.33.1611021431422; Mon, 18 Jan 2021 17:57:11 -0800 (PST) Received: from [10.137.0.20] (ip-86-49-253-127.net.upcbroadband.cz. [86.49.253.127]) by smtp.gmail.com with ESMTPSA id j5sm11758739edl.42.2021.01.18.17.57.10 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 18 Jan 2021 17:57:10 -0800 (PST) Subject: Re: PoC/WIP: Extended statistics on expressions To: Dean Rasheed , Justin Pryzby Cc: PostgreSQL Hackers References: <2567ae7e-e1dd-48b5-054d-ed6ff81c0335@enterprisedb.com> <20210108023537.GA19743@telsasoft.com> <5305f9cf-3927-06c4-cd5b-e46cbc58bc7f@enterprisedb.com> <20210116232208.GB8560@telsasoft.com> <2f2a3b3b-93e4-723f-144e-bc21f10d6b61@enterprisedb.com> <20210118045331.GF8560@telsasoft.com> From: Tomas Vondra Message-ID: <3f20da4d-89dc-0912-98d2-b6f0ef06c87f@enterprisedb.com> Date: Tue, 19 Jan 2021 02:57:05 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.6.0 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 7bit X-CLOUD-SEC-AV-Info: enterprisedb,google_mail,monitor X-CLOUD-SEC-AV-Sent: true X-Gm-Spam: 0 X-Gm-Phishy: 0 List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk On 1/18/21 4:48 PM, Dean Rasheed wrote: > Looking through extended_stats.c, I found a corner case that can lead > to a seg-fault: > > CREATE TABLE foo(); > CREATE STATISTICS s ON (1) FROM foo; > ANALYSE foo; > > This crashes in lookup_var_attr_stats(), because it isn't expecting > nvacatts to be 0. I can't think of any case where building stats on a > table with no analysable columns is useful, so it should probably just > exit early in that case. > > > In BuildRelationExtStatistics(), it looks like min_attrs should be > declared assert-only. > > > In evaluate_expressions(): > > + /* set the pointers */ > + result = (ExprInfo *) ptr; > + ptr += sizeof(ExprInfo); > > I think that should probably have a MAXALIGN(). > Thanks, I'll fix all of that. > > A slightly bigger issue that I don't like is the way it assigns > attribute numbers for expressions starting from > MaxHeapAttributeNumber+1, so the first expression has an attnum of > 1601. That leads to pretty inefficient use of Bitmapsets, since most > tables only contain a handful of columns, and there's a large block of > unused space in the middle the Bitmapset. > > An alternative approach might be to use regular attnums for columns > and use negative indexes -1, -2, -3, ... for expressions in the stored > stats. Then when storing and retrieving attnums from Bitmapsets, it > could just offset by STATS_MAX_DIMENSIONS (8) to avoid negative values > in the Bitmapsets, since there can't be more than that many > expressions (just like other code stores system attributes using > FirstLowInvalidHeapAttributeNumber). > > That would be a somewhat bigger change, but hopefully fairly > mechanical, and then some code like add_expressions_to_attributes() > would go away. > Well, I tried this but unfortunately it's not that simple. We still need to build the bitmaps, so I don't think add_expression_to_attributes can be just removed. I mean, we need to do the offsetting somewhere, even if we change how we do it. But the main issue is that in some cases the number of expressions is not really limited by STATS_MAX_DIMENSIONS - for example when applying functional dependencies, we "merge" multiple statistics, so we may end up with more expressions. So we can't just use STATS_MAX_DIMENSIONS. Also, if we offset regular attnums by STATS_MAX_DIMENSIONS, that inverts the order of processing (so far we've assumed expressions are after regular attnums). So the changes are more extensive - I tried doing that anyway, and I'm still struggling with crashes and regression failures. Of course, that doesn't mean we shouldn't do it, but it's far from mechanical. (Some of that is probably a sign this code needs a bit more work to polish.) But I wonder if it'd be easier to just calculate the actual max attnum and then use it instead of MaxHeapAttributeNumber ... > > Looking at the new view pg_stats_ext_exprs, I noticed that it fails to > show expressions until the statistics have been built. For example: > > CREATE TABLE foo(a int, b int); > CREATE STATISTICS s ON (a+b), (a*b) FROM foo; > SELECT statistics_name, tablename, expr, n_distinct FROM pg_stats_ext_exprs; > > statistics_name | tablename | expr | n_distinct > -----------------+-----------+------+------------ > s | foo | | > (1 row) > > but after populating and analysing the table, this becomes: > > statistics_name | tablename | expr | n_distinct > -----------------+-----------+---------+------------ > s | foo | (a + b) | 11 > s | foo | (a * b) | 11 > (2 rows) > > I think it should show the expressions even before the stats have been built. > > Another issue is that it returns rows for non-expression stats as > well. For example: > > CREATE TABLE foo(a int, b int); > CREATE STATISTICS s ON a, b FROM foo; > SELECT statistics_name, tablename, expr, n_distinct FROM pg_stats_ext_exprs; > > statistics_name | tablename | expr | n_distinct > -----------------+-----------+------+------------ > s | foo | | > (1 row) > > and those values will never be populated, since they're not > expressions, so I would expect them to not be shown in the view. > > So basically, instead of > > + LEFT JOIN LATERAL ( > + SELECT > + * > + FROM ( > + SELECT > + > unnest(pg_get_statisticsobjdef_expressions(s.oid)) AS expr, > + unnest(sd.stxdexpr)::pg_statistic AS a > + ) x > + ) stat ON sd.stxdexpr IS NOT NULL; > > perhaps just > > + JOIN LATERAL ( > + SELECT > + * > + FROM ( > + SELECT > + > unnest(pg_get_statisticsobjdef_expressions(s.oid)) AS expr, > + unnest(sd.stxdexpr)::pg_statistic AS a > + ) x > + ) stat ON true; Will fix. regards -- Tomas Vondra EnterpriseDB: http://www.enterprisedb.com The Enterprise PostgreSQL Company