Received: from maia.hub.org (maia-5.hub.org [200.46.204.29]) by mail.postgresql.org (Postfix) with ESMTP id 87C9CB5D803 for ; Sun, 10 Jul 2011 18:16:43 -0300 (ADT) Received: from mail.postgresql.org ([200.46.204.86]) by maia.hub.org (mx1.hub.org [200.46.204.29]) (amavisd-maia, port 10024) with ESMTP id 50818-03 for ; Sun, 10 Jul 2011 21:16:36 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from nm21-vm0.bullet.mail.ne1.yahoo.com (nm21-vm0.bullet.mail.ne1.yahoo.com [98.138.90.94]) by mail.postgresql.org (Postfix) with SMTP id 2A8CFB5DBF1 for ; Sun, 10 Jul 2011 18:16:35 -0300 (ADT) Received: from [98.138.90.54] by nm21.bullet.mail.ne1.yahoo.com with NNFMP; 10 Jul 2011 21:16:35 -0000 Received: from [98.138.226.57] by tm7.bullet.mail.ne1.yahoo.com with NNFMP; 10 Jul 2011 21:16:35 -0000 Received: from [127.0.0.1] by smtp208.mail.ne1.yahoo.com with NNFMP; 10 Jul 2011 21:16:35 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s1024; t=1310332595; bh=DAYm3XIKTq48TIKlMVdmZB3VINssid4GRaxkOVkOkqY=; h=X-Yahoo-Newman-Id:Received:X-Yahoo-SMTP:X-YMail-OSG:X-Yahoo-Newman-Property:Message-ID:Date:From:User-Agent:MIME-Version:To:Subject:Content-Type:Content-Transfer-Encoding; b=bax/dtoFVNFQd48un04S2UgcD49JlXUIzP+RG21/7sc+GGCz7+IKYU86v7BhOp72AxzuBlEeHy7jYMhLhzDz8f2C9FUmqnP3NrBhRAAfr+rfUeq3yb+qLiXADhY/Ku0gQMdeH+ve4YIH5jGqQJMOeGwP1unja6caI7TQAV7KpLo= X-Yahoo-Newman-Id: 309227.1815.bm@smtp208.mail.ne1.yahoo.com Received: from [192.168.206.5] (lhofhansl@67.170.234.149 with plain) by smtp208.mail.ne1.yahoo.com with SMTP; 10 Jul 2011 14:16:35 -0700 PDT X-Yahoo-SMTP: YmezqLWswBDx0ai534H100MJuqGzDQ-- X-YMail-OSG: RYfrtCcVM1lnnajUzLkhz2LlGwaQQorxvWTY6qs50l_Lf0a bF0nQNivpp_at6HeVvlruDiFlaVm5aiPFfI8ut5ZG4N9OUKyZUmqD9azOQ82 AWLeAcUxmCWF_qrt0Tmt8cDjj21vz5LdDTmUrCkwoMA.kAm_oCBQAklrK4sA BeZ_AgowmqGszEZ.zB9563xh5i1uG84461aDjP71ExKJylMjgc5Q2KPcB8oC OZnjcXBUq6Od4wbUt0c6jF8Q.UJVDVJ_SjqQtycXMjv6T3aW8l5Ygidq0iPh hs.g7bhUxWn3H.4W7Z8Rh5B7lRDtFzzzAqhVTR6OHNMD0Xxqkvu.RxsEAXBn 4.JVyPc.xjwtyDtWqo7ddTw-- X-Yahoo-Newman-Property: ymail-3 Message-ID: <4E1A1696.5010307@yahoo.com> Date: Sun, 10 Jul 2011 14:16:06 -0700 From: lars User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.18) Gecko/20110621 Fedora/3.1.11-1.fc14 Thunderbird/3.1.11 MIME-Version: 1.0 To: pgsql-performance@postgresql.org Subject: Statistics and Multi-Column indexes Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Virus-Scanned: Maia Mailguard 1.0.1 X-Spam-Status: No, hits=-1.584 tagged_above=-10 required=5 tests=BAYES_00=-1.9, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SARE_MILLIONSOF=0.315, T_RP_MATCHES_RCVD=-0.01, T_TO_NO_BRKTS_FREEMAIL=0.01 X-Spam-Level: X-Archive-Number: 201107/88 X-Sequence-Number: 44300 I know this has been discussed various times... We are maintaining a large multi tenant database where *all* tables have a tenant-id and all indexes and PKs lead with the tenant-id. Statistics and counts for the all other columns are only really meaningful within the context of the tenant they belong to. There appear to be five options for me: 1. Using single column indexes on all interesting columns and rely on PostgreSQLs bitmap indexes to combine them (which are pretty cool). 2. Use multi column indexes and accept that sometimes Postgres pick the wrong index (because a non-tenant-id column might seem highly selective over the table, but it is not for a particular tenant - or vice versa). 3. Use a functional index that combines multiple columns and only query via these, that causes statistics gathering for the expression. I.e. create index i on t((tenantid||column1)) and SELECT ... FROM t WHERE tenantid||column1 = '...' 4. Play with n_distinct and/or set the statistics for the inner columns to some fixed values that lead to the plans that we want. 5. Have a completely different schema and maybe a database per tenant. Currently we use Oracle and query hinting, but I do not like that practice at all (and Postgres does not have hints anyway). Are there any other options? #1 would be the simplest, but I am concerned about the overhead, both maintaining two indexes and building the bitmap during queries - for every query. I don't think #2 is actually an option. We have some tenants with many (sometimes 100s) millions of rows per table, and picking the wrong index would be disastrous. Could something like #3 be generally added to Postgres? I.e. if there is a multi column index keep combined statistics for the involved columns. Of course in that case is it no longer possible to query the index by prefix. #3 also seems expensive as the expression needs to be evaluated for each changed row. Still trying #4. I guess it involves setting the stat target for the inner columns to 0 and then inserting my own records into pg_statistic. Probably only setting n_distinct, i.e. set it "low" if the inner column is not selective within the context of a tenant and "high" otherwise. For various reasons #5 is also not an option. And of course the same set of questions comes up with joins. Thanks. -- Lars