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 1hbpwE-0003rN-Gg for pgsql-hackers@arkaria.postgresql.org; Fri, 14 Jun 2019 17:24:30 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1hbpwD-0008A6-6g for pgsql-hackers@arkaria.postgresql.org; Fri, 14 Jun 2019 17:24:29 +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 1hbpwC-00089z-UG for pgsql-hackers@lists.postgresql.org; Fri, 14 Jun 2019 17:24:28 +0000 Received: from mail-qt1-f195.google.com ([209.85.160.195]) by magus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1hbpw8-0005Tt-Br for pgsql-hackers@postgresql.org; Fri, 14 Jun 2019 17:24:28 +0000 Received: by mail-qt1-f195.google.com with SMTP id y57so3373894qtk.4 for ; Fri, 14 Jun 2019 10:24:24 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:reply-to:subject:to:cc:references:from :organization:message-id:date:user-agent:mime-version:in-reply-to :content-language:content-transfer-encoding; bh=FsXxFOAsw1cUqxpj2anF6qpyq1gu52k4joH3w0RU2ME=; b=JrVt6CciImYtLf1YurgGLKV4dbhmT41jn7EsZmSh/sWRUiO8zCErnWxJ6dWxwd8Jge IzjT+KbOFbLpfkeyPrISLXHuW9j5h+UHiKII8qZ4sP7jEy+/hJ/ddV7cFW5DIt5N1KXm pYxHrgE+WVs+IjQbfHtcN279ag5bIcgSXwkbxXO2+JmdczTh/COgfkXnQTUY/SbiYugH TunCUAjAknWHp3+q41u7T9oONemsSe66Kiu6GspxfWafRlcDlSn1QDpif19V/IJH5j+4 U1i8AbnuDf/OpB3AmVDamtergc4hQDu7OK2Lwo3aGmecCRHtZp1djWTEibeU3hnHWYC+ yMjw== X-Gm-Message-State: APjAAAXBJxl5cCDFCYyWheKKLPPQn8EWmwNkG//hlZaitYnQjnIeqjpj LfAoEm4QucLtB7qmOj5sPAklqQ== X-Google-Smtp-Source: APXvYqzvb7TcYkghL2YUeEXmBkzjpNALs8I6x6FmalKjfhFjSs3CVWogxMas6UhKida0B7sio0mfNQ== X-Received: by 2002:a0c:888a:: with SMTP id 10mr9562983qvn.0.1560533062871; Fri, 14 Jun 2019 10:24:22 -0700 (PDT) Received: from localhost.localdomain (c-24-61-8-151.hsd1.ma.comcast.net. [24.61.8.151]) by smtp.gmail.com with ESMTPSA id h185sm2120078qkd.11.2019.06.14.10.24.21 (version=TLS1_3 cipher=AEAD-AES128-GCM-SHA256 bits=128/128); Fri, 14 Jun 2019 10:24:22 -0700 (PDT) Reply-To: jesper.pedersen@redhat.com Subject: Re: Index Skip Scan To: David Rowley Cc: Floris Van Nee , Dmitry Dolgov <9erthalion6@gmail.com>, Rafia Sabih , Jeff Janes , Thomas Munro , Alexander Kuzmenkov , Peter Geoghegan , Tomas Vondra , Thomas Munro , Bhushan Uparkar , PostgreSQL-development , Alexander Korotkov , James Coleman References: <2685f020-f302-9bf6-1b5c-ebc2bcebc635@2ndquadrant.com> <20190315.125452.252656146.horiguchi.kyotaro@lab.ntt.co.jp> <1559361698401.22864@Optiver.com> <1559362223126.18661@Optiver.com> <988b7763-5c55-1be1-b7b6-f3a68eff0d40@redhat.com> <1559763453006.85615@Optiver.com> <1559763570329.85227@Optiver.com> <4d469bf2-49ff-bc3d-a428-6c7b5d87d526@redhat.com> From: Jesper Pedersen Organization: Red Hat Message-ID: <9b36ad5c-53c2-47cc-2cc7-10588d24cb47@redhat.com> Date: Fri, 14 Jun 2019 13:24:20 -0400 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.7.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 List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk Hi David, On 6/14/19 3:19 AM, David Rowley wrote: > I read over this thread a few weeks ago while travelling back from > PGCon. (I wish I'd read it on the outward trip instead since it would > have been good to talk about it in person.) > > First off. I think this is a pretty great feature. It certainly seems > worthwhile working on it. > > I've looked over the patch just to get a feel for how the planner part > works and I have a few ideas to share. > > The code in create_distinct_paths() I think should work a different > way. I think it would be much better to add a new field to Path and > allow a path to know what keys it is distinct for. This sort of goes > back to an idea I thought about when developing unique joins > (9c7f5229ad) about an easier way to detect fields that a relation is > unique for. I've been calling these "UniqueKeys" in a few emails [1]. > The idea was to tag these onto RelOptInfo to mention which columns or > exprs a relation is unique by so that we didn't continuously need to > look at unique indexes in all the places that call > relation_has_unique_index_for(). The idea there was that unique joins > would know when a join was unable to duplicate rows. If the outer side > of a join didn't duplicate the inner side, then the join RelOptInfo > could keep the UniqueKeys from the inner rel, and vice-versa. If both > didn't duplicate then the join rel would obtain the UniqueKeys from > both sides of the join. The idea here is that this would be a better > way to detect unique joins, and also when it came to the grouping > planner we'd also know if the distinct or group by should be a no-op. > DISTINCT could be skipped, and GROUP BY could do a group aggregate > without any sort. > > I think these UniqueKeys ties into this work, perhaps not adding > UniqueKeys to RelOptInfo, but just to Path so that we create paths > that have UniqueKeys during create_index_paths() based on some > uniquekeys that are stored in PlannerInfo, similar to how we create > index paths in build_index_paths() by checking if the index > has_useful_pathkeys(). Doing it this way would open up more > opportunities to use skip scans. For example, semi-joins and > anti-joins could make use of them if the uniquekeys covered the entire > join condition. With this idea, the code you've added in > create_distinct_paths() can just search for the cheapest path that has > the correct uniquekeys, or if none exist then just do the normal > sort->unique or hash agg. I'm not entirely certain how we'd instruct > a semi/anti joined relation to build such paths, but that seems like a > problem that could be dealt with when someone does the work to allow > skip scans to be used for those. > > Also, I'm not entirely sure that these UniqueKeys should make use of > PathKey since there's no real need to know about pk_opfamily, > pk_strategy, pk_nulls_first as those all just describe how the keys > are ordered. We just need to know if they're distinct or not. All > that's left after removing those fields is pk_eclass, so could > UniqueKeys just be a list of EquivalenceClass? or perhaps even a > Bitmapset with indexes into PlannerInfo->ec_classes (that might be > premature for not since we've not yet got > https://commitfest.postgresql.org/23/1984/ or > https://commitfest.postgresql.org/23/2019/ ) However, if we did use > PathKey, that does allow us to quickly check if the UniqueKeys are > contained within the PathKeys, since pathkeys are canonical which > allows us just to compare their memory address to know if two are > equal, however, if you're storing eclasses we could probably get the > same just by comparing the address of the eclass to the pathkey's > pk_eclass. > > Otherwise, I think how you're making use of paths in > create_distinct_paths() and create_skipscan_unique_path() kind of > contradicts how they're meant to be used. > Thank you very much for this feedback ! Will need to revise the patch based on this. > I also agree with James that this should not be limited to Index Only > Scans. From testing the patch, the following seems pretty strange to > me: > > # create table abc (a int, b int, c int); > CREATE TABLE > # insert into abc select a,b,1 from generate_Series(1,1000) a, > generate_Series(1,1000) b; > INSERT 0 1000000 > # create index on abc(a,b); > CREATE INDEX > # explain analyze select distinct on (a) a,b from abc order by a,b; -- > this is fast. > QUERY PLAN > ----------------------------------------------------------------------------------------------------------------------------- > Index Only Scan using abc_a_b_idx on abc (cost=0.42..85.00 rows=200 > width=8) (actual time=0.260..20.518 rows=1000 loops=1) > Scan mode: Skip scan > Heap Fetches: 1000 > Planning Time: 5.616 ms > Execution Time: 21.791 ms > (5 rows) > > > # explain analyze select distinct on (a) a,b,c from abc order by a,b; > -- Add one more column and it's slow. > QUERY PLAN > ------------------------------------------------------------------------------------------------------------------------------------------ > Unique (cost=0.42..50104.43 rows=200 width=12) (actual > time=1.201..555.280 rows=1000 loops=1) > -> Index Scan using abc_a_b_idx on abc (cost=0.42..47604.43 > rows=1000000 width=12) (actual time=1.197..447.683 rows=1000000 > loops=1) > Planning Time: 0.102 ms > Execution Time: 555.407 ms > (4 rows) > > [1] https://www.postgresql.org/search/?m=1&q=uniquekeys&l=1&d=-1&s=r > Ok, understood. I have put the CF entry into "Waiting on Author". Best regards, Jesper