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 1gs5pv-0004q9-0T for pgsql-performance@arkaria.postgresql.org; Fri, 08 Feb 2019 13:04:55 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1gs5pt-0005By-Fg for pgsql-performance@arkaria.postgresql.org; Fri, 08 Feb 2019 13:04:53 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1gs5ps-00056B-V4 for pgsql-performance@lists.postgresql.org; Fri, 08 Feb 2019 13:04:53 +0000 Received: from mail-it1-x135.google.com ([2607:f8b0:4864:20::135]) by makus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1gs5pp-0008W2-DH for pgsql-performance@postgresql.org; Fri, 08 Feb 2019 13:04:51 +0000 Received: by mail-it1-x135.google.com with SMTP id q78so8589572itc.0 for ; Fri, 08 Feb 2019 05:04:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=telsasoft-com.20150623.gappssmtp.com; s=20150623; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:content-transfer-encoding:in-reply-to :user-agent; bh=hwsL45j865XkWGdTRxtRAotIDhGku5TXU7xEA/6zYos=; b=VU+3b4WbbDOxjYXMiRTnBMi8DoRqoqNmmhYgjvUt0E1PclwuG4KHItj5jwlp2B4y5i NoLw6dK0un8CfLmFXVl4fQuGK4A+rpNm4wOR1boXXaT6u0aDAop8tL8baTPYOkdvXVmY VIgkedvqFxnAlqhdSTM+Ntb5sSX862LiB+O1j3JgF/RNrTmIoM3yP1BCYHO70bt0duFN EcyXzSx4MjrRLvC32KLkBnpmrnLFcLxlSsEojvFtLE09Qw0GFqjgv9DhytdGkYg4GOrn 7+7B56XrPjjz3IXWuq6NWrEzz+9PNjnor0tQWCJTRA6Q2owDpI1H2p51aslhDri1B1Gw BH9w== 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:content-transfer-encoding :in-reply-to:user-agent; bh=hwsL45j865XkWGdTRxtRAotIDhGku5TXU7xEA/6zYos=; b=caNZQMH7+aXR8dh2gy6LG6yGklt8p3VgHWpI7Ukc2fTo1u39bafyjyD8yXbLhkBBYk lcru1cdLwW4WH1ThGoWn8S2izpXzzBV8pvmpLa23zOGzIr9oFsNV2MeK7N2CZlK9DXQt mQ3lU9ysZJdPtuqj2vuHSGLaW9O1hUEf7mJsVX5395AKllNuhhAATGxVwHXvzCSX+n4W V9FjDAbpvqIQ6AiP2lXboTT4V4D5sYlryB7uG2lFK+YfPa4NuXT+Gwzb8M3Yq6xT1F1j yuOGgwB25NVdF2xNfDAkF7vlPshSIlAz/LWHeuh5wfPlJXXw1XHw2qKLs1bzUsd8x+WD MglQ== X-Gm-Message-State: AHQUAub3VklAv+jL4Nj8DrTnNgkC6GmIi2B1tltzPKGtB6Eo1OGqGRJ1 nac0GXw16TuU2P1frRZQEGtiJHeYGPs= X-Google-Smtp-Source: AHgI3IYM8o9z6rIcLkVaholU9iN7hvxSnLcyP1tnRituqNOqXPuIrm4BTaCagm2bSkZieoxrst88iw== X-Received: by 2002:a02:c94f:: with SMTP id u15mr11840666jao.32.1549631087954; Fri, 08 Feb 2019 05:04:47 -0800 (PST) Received: from pryzbyj (charmander.telsasoft.com. [50.244.222.1]) by smtp.gmail.com with ESMTPSA id k12sm366280iop.8.2019.02.08.05.04.45 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 08 Feb 2019 05:04:46 -0800 (PST) Received: by pryzbyj (Postfix, from userid 1000) id BDE44800BD7; Fri, 8 Feb 2019 07:04:44 -0600 (CST) Date: Fri, 8 Feb 2019 07:04:44 -0600 From: Justin Pryzby To: keith anderson Cc: "pgsql-performance@postgresql.org" Subject: Re: Partitioning Optimizer Questions and Issues Message-ID: <20190208130444.GC29720@telsasoft.com> References: <1233297695.414916.1549624431535.ref@mail.yahoo.com> <1233297695.414916.1549624431535@mail.yahoo.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable In-Reply-To: <1233297695.414916.1549624431535@mail.yahoo.com> User-Agent: Mutt/1.5.23 (2014-03-12) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk On Fri, Feb 08, 2019 at 11:13:51AM +0000, keith anderson wrote: > So to summarise the findings/questions from above: > - It seems like the Postgres optimizer sometimes uses the partition level= statistics, and sometimes the global table level statistics? Or is it usin= g something else?- With partitioning tables with unique identifier and retr= ieving explicitly on those identifiers, at present the optimizer will alway= s understimate the selectivity and overestimate the rows returned. This ina= ccuracy increases in proportion to the number of partitions.- As a result, = when joining to other tables, you are liable to hitting sequential scans. T= his becomes more likely as you have more partitions or if join to more part= itioned tables (note I am aware I could try and tune random_page_cost to tr= y and prevent this).- To me in the examples queries described above, it mak= es sense to use the partition statistics for the partition level access str= ategy, but the global statistics when estimating the actual rows returned b= y all the individual partition queries. Is there a reason not to do this? O= r do others believe the optimizer is doing the right thing here? > And then some general questions: > - How do other people use partitioning but without a significant performa= nce disadvantage on reading the data? Is there something else I should be d= oing here to achieve the same thing without the overhead? At present my rea= ds have increased optimization cost (as it needs to optimize access to each= partition) and also execution cost (access the index on every partition). = Even without the optimizer issues described above, the cost of reading simp= le data is extremely high relative to non-partitioned data (unless you use = the partition key as a filter for each table to eliminate those partitions)= =2E- Is there any chance/plan to add global indexes to postgres? If so woul= d that impact significantly the cost of the partition drop e.g. to clean up= the index. > Thanks in advance for any feedback/support, An equality or IN() query will use the pg_stats most-common-values list, whereas a range query will use the histogram. The tables probably doesn't have complete MCV list. By default, that's lim= ited to 100 entries. Since the maximum allowed by ALTER..SET STATISTICS is 10k,= I don't think it'll help to change it (at least for your production use case). Each partition's rowcount appears to be estimated from its ndistinct, and n= ot =66rom its content, so each is estimated as having about the same rowcount. Your partitions are sharing a sequence for their ID column, which causes the DEFAULT IDs to be unique...but their global uniqueness isn't enforced nor guaranteed. Note, in postgres11, it's possible to create an index on the parent table. It's NOT a global index, but it can be unique if it includes the partition = key. I don't know how closely your example describes your real use case, but I d= on't think that helps with your example; it doesn't seems useful to partition on= a serial column. You seem to be adding unnecessary CHECK constraints that duplicate the partition bounds. Note, it's still useful to include CHECK constraints on = key column if you're planning on DETACHing and re-ATTACHing the partitions, in order to avoid seqscan to verify tuples don't violate specified bounds. You might need to rethink your partitioning scheme - you should choose one = that causes performance to improve, and probably naturally includes the partition key in most queries. Perhaps you'd use 2 levels of partitioning: a RANGE partition by date, which allows for archiving, and a HASH partition by ID, which allows for partition pruning. Note that it's also possible to partition on multiple keys, like RANGE(id,date) - I don't think that's useful here, though. PG11 also allow= s a "default" partition. Or perhaps you could partition by RANGE(date) but add CHECK constraints on = ID, after the table is fully populated, to optimize queries by allowing for partition pruning. Or you could maybe change the ID column to include the timestamp (like BIND zonesfiles YYYYMMDDNNNNNNNN). You'd set a bigint sequence on each partitio= n's ID as default to the beginning of the month. A bigint is enough to handle 5*10^4 times your volume: 20190401000020111222. (I think this is trying to= be unnecessarily clever, unless there's some reason the other two ideas don't work.) Justin