Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtp (Exim 4.84_2) (envelope-from ) id 1eKq8x-0008VA-FN for pgsql-performance@arkaria.postgresql.org; Fri, 01 Dec 2017 18:34:35 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.84_2) (envelope-from ) id 1eKq8w-0000ZX-LN for pgsql-performance@arkaria.postgresql.org; Fri, 01 Dec 2017 18:34:34 +0000 Received: from makus.postgresql.org ([2001:4800:1501:1::229]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1eKq8w-0000ZO-74 for pgsql-performance@lists.postgresql.org; Fri, 01 Dec 2017 18:34:34 +0000 Received: from mail-it0-x241.google.com ([2607:f8b0:4001:c0b::241]) by makus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1eKq8r-0004vl-VV for pgsql-performance@lists.postgresql.org; Fri, 01 Dec 2017 18:34:32 +0000 Received: by mail-it0-x241.google.com with SMTP id p139so3483116itb.1 for ; Fri, 01 Dec 2017 10:34:29 -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=PrHVJvX/22AK1/8Lr3ZD5um+pC6bJjPku7PW4RLEkik=; b=EDGUsPe85Okd4BlD8FNbilWdJizI6bxXLMP7nwqDkrz1CwvDqk1LnUHI7MYhCx0bp1 hQRLY8kzff0QfhkkLDgkGsD3iZqP4gZKFen3Y/K8iLfEnSwKe0vtV+HmVbrmyfwzgdMn YvjsHE8URniWqhap+PuQUQ7ms0ofYDxb0gj+WpBINUdpwfEv/ZRtdikRK9OmkjdggPdT 8kbUHVZIdynFqaqo0ijl/vMWmZZ5zuB7T2bfIzsPnv6ZQ1DrVbjQIH1fg9W+zRIarYZA fbdC/IL1BwID7+lO0fMTe+BmEKISNMTcxLoCa7pJp6ijXhxFUoSuZB43S4UQb2X/y9v2 mEHw== 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=PrHVJvX/22AK1/8Lr3ZD5um+pC6bJjPku7PW4RLEkik=; b=NthIJJXYjHb47JeC29+6TnAqQJD7/roZOwl6TvljpGch4cvmv6mONqeemVwLMLZC/H 6BTwQvHCzLGLacVdWcA/IbPffXPdqIrYaG1ADOL3h06KCIk454zAfJjz11OK782RMs3D uRuU+bjmkK4EkqXBiPoGwrCyAufw9LNtk0NqrUBZvU2ggsRhFhiQzqi7zY9vzuInICvs uYP1H3jaPfhfI0uS93VCvGSUP6QEHwZP7qrrpnPLhwpusfc+7iOwS9y8vxvg8mF8Xztc VfdzLgwGfMH/7X0qa/Jn4Ga2j0wg5O+tEifCfASv7dPvsTFC7I/NLHI8d5wZUa+7GVVR CkKg== X-Gm-Message-State: AKGB3mL5tjf6rx0kWQJ1QhGpA8ldUnOV59DOIyqL+KTuMUeD0FAT3Hfn nv/LFhv8BKZd5Otnhu/7RRaQ4A== X-Google-Smtp-Source: AGs4zMZas6OJcg0ekHaaAQVdc6EvTf5Wq485tF+c9nWESKOGpDP5OnG65r3EcPpEgYKY+0zPMy1hcQ== X-Received: by 10.36.25.20 with SMTP id b20mr3272003itb.31.1512153269025; Fri, 01 Dec 2017 10:34:29 -0800 (PST) Received: from pryzbyj (charmander.telsasoft.com. [50.244.222.1]) by smtp.gmail.com with ESMTPSA id i76sm839704itf.3.2017.12.01.10.34.28 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 01 Dec 2017 10:34:28 -0800 (PST) Received: by pryzbyj (Postfix, from userid 1000) id 95E0780102F; Fri, 1 Dec 2017 12:34:27 -0600 (CST) Date: Fri, 1 Dec 2017 12:34:27 -0600 From: Justin Pryzby To: Vitaliy Garnashevich Cc: pgsql-performance@lists.postgresql.org Subject: Re: Bitmap scan is undercosted? Message-ID: <20171201183427.GK18413@telsasoft.com> References: <73a4936d-2814-dc08-ed0c-978f76f435b0@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: <73a4936d-2814-dc08-ed0c-978f76f435b0@gmail.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, Dec 01, 2017 at 07:40:08PM +0200, Vitaliy Garnashevich wrote: > We recently had an issue in production, where a bitmap scan was chosen > instead of an index scan. Despite being 30x slower, the bitmap scan had > about the same cost as the index scan. Me too, see also: https://www.postgresql.org/message-id/flat/CAH2-WzkRTggiy_LKQUu-oViyp6y_Hhz-a1yWacPy4tcYWV1HoA%40mail.gmail.com#CAH2-WzkRTggiy_LKQUu-oViyp6y_Hhz-a1yWacPy4tcYWV1HoA@mail.gmail.com > drop table if exists aaa; > create table aaa as select (id%100)::int num, (id%10=1)::bool flag from > generate_series(1, 10000000) id; > create index i1 on aaa  (num); > create index i2 on aaa  (flag); > analyze aaa; > > select relname, reltuples::bigint, relpages::bigint, > (reltuples/relpages)::bigint tpp from pg_class where relname > in('aaa','i1','i2') order by relname; > "aaa";9999985;44248;226 > "i1";9999985;27422;365 > "i2";9999985;27422;365 > > The query was: > explain (analyze,verbose,costs,buffers) > select count(*) from aaa where num = 1 and flag = true; Note that id%100==1 implies flag='t', so the planner anticipates retrieving fewer rows than it will ultimately read, probably by 2x. It makes sense that causes the index scan to be more expensive than expected, but that's only somewhat important, since there's no joins involved. The reason why it's more than a bit slower is due to the "density" [0] of the heap pages read. num=1 is more selective than flag=true, so it scans i1, reading 1% of the whole table. But it's not reading the first 1% or some other 1% of the table, it reads tuples evenly distributed across the entire table (226*0.01 = ~2 rows of each page). Since the index was created after the INSERT, the repeated keys (logical value: id%100) are read in physical order on the heap, so this is basically doing a seq scan, but with the additional overhead of reading the index, and maybe doing an fseek() before each/some read()s, too. You could confirm that by connecting strace to the backend before starting the query. Since you did that using % and with indices added after the INSERT, you can't improve it by reindexing (as I was able to for my case). That's an elegant test case, so thanks. I think shared_buffers=512MB is just small enough for this test to be painful for 1e7 rows. I see the table+index is 559MB. I don't know if that's really similar to your production use case, but I would recommend trying BRIN indices, which always require a bitmap scan. Note that some things (like max()) that can use an btree index cannot use brin. PG10.1 has WITH autosummarize, which was important for our use, since we rarely do UPDATEs or DELETEs so tables are rarely vacuumed (only analyzed). Justin [0] I'm borrowing Jeff's language from here: https://www.postgresql.org/message-id/CAMkU%3D1xwGn%2BO0jhKsvrUrbW9MQp1YX0iB4Y-6h1mEz0ffBxK-Q%40mail.gmail.com "density" wasn't our problem, but it's a perfect description of this issue.