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 1hjn4i-0005jJ-K8 for pgsql-performance@arkaria.postgresql.org; Sat, 06 Jul 2019 15:58:08 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1hjn4g-00008a-37 for pgsql-performance@arkaria.postgresql.org; Sat, 06 Jul 2019 15:58:06 +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_SHA1:256) (Exim 4.89) (envelope-from ) id 1hjn4f-00008N-Qh for pgsql-performance@lists.postgresql.org; Sat, 06 Jul 2019 15:58:05 +0000 Received: from mail-wr1-x442.google.com ([2a00:1450:4864:20::442]) by magus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1hjn4X-0001MD-C6 for pgsql-performance@lists.postgresql.org; Sat, 06 Jul 2019 15:58:04 +0000 Received: by mail-wr1-x442.google.com with SMTP id x4so12700601wrt.6 for ; Sat, 06 Jul 2019 08:57:56 -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=3NU50j/QdTJUmYV0xHbN06cgRmMdvJfmFHeb2p/PLlM=; b=1yiKWfatt5ytbYIbZgyYpXIAG7ToBHLWk3aMUwaLB1tf4XfQeP/2Y/JBIDPpSc8fth v8sx2/7YZsIUkWeEJXd9nRZ7d+c+3BiR2pMyNaxSP6zOtihXsfkv80nUIi32jNrIRat+ EwfT9rKYVEqg6w1fyxfta0uuTk1wZNntiPyWvyR+tZ5CxqgZyRdmq8FIt25/xjiciPXZ jFNx3SzJ0aGVD5GglyG/vNmKvCCsoj5+ELQii6aFc1w4xJXPwZhjX16WR4AiivweqI45 OQdK4aWTcFYK8FfHFs7RT0TX8Xf+r++jbw0p5c6bftrz1Dcl9g7WS3CSIFpeAH0ZDDXT kXJw== 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=3NU50j/QdTJUmYV0xHbN06cgRmMdvJfmFHeb2p/PLlM=; b=r/nFHoejNhkySSxp2YBkwYyrdi70InExtYE9mTjoDZ4/CQxxQCzhGVA5Sap1ZzC6tc uGYZB1SdiQcUy1OaEpnjnx3a8jTWdk1u65PwRF02nM9jaG2++bwuNjJU8C4yBlxz7G9n zQoRsu8qg9D6mmkNsaTVUBXhiUb8EswVjYDL0/Ed1XwdUdyrzjqILLD4X7wtbbBIRdrh gIHY4E3/iv5DJxq9Kz4QjS5QExGo+gQhDjRWKOGuDTjP5LESr/0FB4Vs3M54P/fZ2d7G 1wtCEmyCkL79ZdbOioWaZOx0iK3bbb0IxP6W990f4QjRc/YldXitneNmhUlSdar0qOly Qg3g== X-Gm-Message-State: APjAAAXxK9ZEmo6Q4NKTaI4CFI2MPX0dy4Au29WxqSjShRK3pOeQ6OO3 qDWATd4bltakN4NRXnAEfwh1Bw== X-Google-Smtp-Source: APXvYqwBvaJkqOolmKSg8y6EdkaicP8zXDzfwxtpRo5XfKttor4W/3T0jOxhzC43hMAYAANYhiohyA== X-Received: by 2002:a5d:430c:: with SMTP id h12mr9512839wrq.163.1562428675889; Sat, 06 Jul 2019 08:57:55 -0700 (PDT) Received: from localhost (ip-86-49-253-160.net.upcbroadband.cz. [86.49.253.160]) by smtp.gmail.com with ESMTPSA id i18sm11886025wrp.91.2019.07.06.08.57.54 (version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256); Sat, 06 Jul 2019 08:57:54 -0700 (PDT) Date: Sat, 6 Jul 2019 17:57:53 +0200 From: Tomas Vondra To: Ancoron Luciferis Cc: pgsql-performance@lists.postgresql.org Subject: Re: Custom opclass for column statistics? Message-ID: <20190706155753.4yf5i4lezx42x5os@development> References: <20190706133858.n7lj4wrte6ulcvk3@development> <8ef092e6-d0c1-4f7a-86ae-e708e1322337@googlemail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Disposition: inline In-Reply-To: <8ef092e6-d0c1-4f7a-86ae-e708e1322337@googlemail.com> User-Agent: NeoMutt/20180716-1444-295967 List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk On Sat, Jul 06, 2019 at 05:35:33PM +0200, Ancoron Luciferis wrote: >On 06/07/2019 15:38, Tomas Vondra wrote: >> On Sat, Jul 06, 2019 at 11:02:27AM +0200, Ancoron Luciferis wrote: >>> Hi, >>> >>> I've been wondering whether it is possible somehow to have the standard >>> column statistics to respect a certain operator class? >>> >>> The reason why I am asking for this is that I have a UUID column with a >>> unique index at it using a custom operator class which implies a >>> different sort order than for the default UUID operator class. >>> >>> This results into planner mistakes when determining whether to use the >>> index for row selection or not. Too often it falls back into sequential >>> scan due to this. >>> >> >> Can you share an example demonstrating the issue? >> >> >> regards >> > >Yes, I have an opclass as follows: > >CREATE OPERATOR CLASS uuid_timestamp_ops FOR TYPE uuid > USING btree AS > OPERATOR 1 <*, > OPERATOR 1 <~ (uuid, timestamp with time zone), > OPERATOR 2 <=*, > OPERATOR 2 <=~ (uuid, timestamp with time zone), > OPERATOR 3 =, > OPERATOR 3 =~ (uuid, timestamp with time zone), > OPERATOR 4 >=*, > OPERATOR 4 >=~ (uuid, timestamp with time zone), > OPERATOR 5 >*, > OPERATOR 5 >~ (uuid, timestamp with time zone), > FUNCTION 1 uuid_timestamp_cmp(uuid, uuid), > FUNCTION 1 uuid_timestamp_only_cmp(uuid, timestamp >with time zone), > FUNCTION 2 uuid_timestamp_sortsupport(internal) >; > >...and e.g. operator "<*" is defined as: > >CREATE FUNCTION uuid_timestamp_lt(uuid, uuid) >RETURNS bool >AS 'MODULE_PATHNAME', 'uuid_timestamp_lt' >LANGUAGE C >IMMUTABLE >LEAKPROOF >STRICT >PARALLEL SAFE; > >COMMENT ON FUNCTION uuid_timestamp_lt(uuid, uuid) IS 'lower than'; > >CREATE OPERATOR <* ( > LEFTARG = uuid, > RIGHTARG = uuid, > PROCEDURE = uuid_timestamp_lt, > COMMUTATOR = '>*', > NEGATOR = '>=*', > RESTRICT = scalarltsel, > JOIN = scalarltjoinsel >); > > >The function "uuid_timestamp_lt" is basically defined as follows: >1. if not version 1 UUID fallback to standard uuid compare >2. extract timestamp values and compare >3. if equal timestamps fallback to standard uuid compare > >...so that a chronological order is established. > > >The test table is created as follows: > >CREATE TABLE uuid_v1_ext (id uuid); >CREATE UNIQUE INDEX idx_uuid_v1_ext ON uuid_v1_ext (id uuid_timestamp_ops); > > >The values for "histogram_bounds" of the test table look like this (due >to the default sort order for standard type UUID): > >00003789-97bf-11e9-b6bb-e03f49f7f733 >008b88f8-6deb-11e9-901a-e03f4947f477 >010a8b22-586a-11e9-8258-e03f49ce78f3 >... >6f682e68-978d-11e9-901a-e03f4947f477 >6ff412ee-926f-11e9-901a-e03f4947f477 >7079ffe2-642f-11e9-b0cc-e03f49e7fd3b >70ffaeca-4645-11e9-adf9-e03f494677fb >... >fef26b41-9b9d-11e9-b0cc-e03f49e7fd3b >ff779ce8-9e52-11e9-8258-e03f49ce78f3 >ffff6bfc-4de4-11e9-b0d4-e03f49d6f6bf > >...and I think that's where the planner gets the decision for a query >such as: > >DELETE FROM uuid_v1_ext WHERE id <* '4bdf6f81-56ad-11e9-8258-e03f49ce78f3'; > >...which then get's executed as sequential scan instead of an index scan. > >I was also thinking about changing the selectivity function used by the >custom operator, but I didn't find any hints how to implement that >without duplicating a lot of internal code. > Not sure, I'm not very familiar with this code, so I'd have to play with it and try things. But that's hard when I don't have any code. Would it be possible to share a small self-contained test case? I wonder what does uuid_timestamp_cmp do? I suppose it first compares by a timestamp extracted from the UUID, right? It'd be interesting to see (a) statistics for the column from pg_stats, both for the table and index (which should have been built using the custom opclass, I think). (b) EXPLAIN ANALYZE for queries with your opclass, and perhaps with the default one (that can't use the timestamp condition, but it should be possible to generate smallers/largest uuid for a timestamp). BTW which PostgreSQL version is this? regards -- Tomas Vondra http://www.2ndQuadrant.com PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services