Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtp (Exim 4.84_2) (envelope-from ) id 1eKpIN-0005V5-7W for pgsql-performance@arkaria.postgresql.org; Fri, 01 Dec 2017 17:40:15 +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 1eKpIM-0004I2-Qq for pgsql-performance@arkaria.postgresql.org; Fri, 01 Dec 2017 17:40:14 +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 1eKpIM-0004Hf-Gx for pgsql-performance@lists.postgresql.org; Fri, 01 Dec 2017 17:40:14 +0000 Received: from mail-yw0-x241.google.com ([2607:f8b0:4002:c05::241]) by makus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1eKpIJ-0003iS-RO for pgsql-performance@lists.postgresql.org; Fri, 01 Dec 2017 17:40:13 +0000 Received: by mail-yw0-x241.google.com with SMTP id y187so4314224ywd.12 for ; Fri, 01 Dec 2017 09:40:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=to:from:subject:message-id:date:user-agent:mime-version :content-transfer-encoding:content-language; bh=duh6l/VU1rKCk817cozPqXV9RCd2VsYhVcS0FPmW16c=; b=aijkLVtzykWAmf7Xu6k3GWNJMFJ34H7xkr0nka8TdPt1FnocZy4A0NS3m3IPFF3x93 /+PghZBvpTbG25nuyDOAF4oRuSAjQxZzvU9Q7GrtdwTJsPUSOGxfnxQQRF/Z3IwomchD bEl2JjXGoQ+p0Yh7iOabvPFc9MxXi9TYHuPM6Bh1rJmuDk/UEw9VJssf/5IllaA95IyT H5Wppt+vgfPB/jz1YczVEQ2/vTJmTAFIFu41ir8oSfZYYDx+NHclQT9GnvYZjWPoDCfD ryRLcVubzY4dFcT5+07TtTZRs95wW4PQwba3uyAF2Ui3XzPXE31KfN/b5gORQrNbQpMO UIBg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:to:from:subject:message-id:date:user-agent :mime-version:content-transfer-encoding:content-language; bh=duh6l/VU1rKCk817cozPqXV9RCd2VsYhVcS0FPmW16c=; b=pJzyvogqjmlpongmbSz90maSBIBgFq5G2kTrvHpD9VIZUlNtK0JpYagdKUD1Nu1SlH aqmr5wKJRzRx91jDHTjIh63lVy6WpodI2GOiK7X2pViVxnLPheBy164XByPUg3zDKDIJ 35SCSKDCkarvEZMI0QdgSa55aL5sR/SI+BCcti698ObeOvv344Ng1PawLMNjmL+qG63v Khfg/L2XotqiUt8BCn15H9UCZD66MoDuSUopIrgv80odba9FK45A0kR3P9QXIt7Nvqjn rgoAZ9lspeE14jMF9EEfcFzIbbU8RGWE/7LrhNnsu/RflIsksrx7Jiu4xiydyXOJIidE hyEg== X-Gm-Message-State: AJaThX5Mp3Oz9A1JW56tLaxbY7i/FDTML/9zHjWnRu3WwYAfJTPoIvpM 008yBA8+dcXsL37/cxPsRCiTV/Bw X-Google-Smtp-Source: AGs4zMaLcB6MIVj3PpkfySVDYX69APwHyLYDAsUJNj7eTMLxdDcF2uKeBlHFfKpbyDLoPfrXrvcQkA== X-Received: by 10.129.123.197 with SMTP id w188mr4336938ywc.409.1512150010564; Fri, 01 Dec 2017 09:40:10 -0800 (PST) Received: from [192.168.1.151] ([178.54.41.83]) by smtp.gmail.com with ESMTPSA id h21sm3149186ywk.43.2017.12.01.09.40.09 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 01 Dec 2017 09:40:10 -0800 (PST) To: pgsql-performance@lists.postgresql.org From: Vitaliy Garnashevich Subject: Bitmap scan is undercosted? Message-ID: <73a4936d-2814-dc08-ed0c-978f76f435b0@gmail.com> Date: Fri, 1 Dec 2017 19:40:08 +0200 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.0) Gecko/20100101 Thunderbird/52.5.0 MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit Content-Language: en-US List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk Hi, 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. I've found some cases where similar issues with bitmap scans were reported before: https://www.postgresql.org/message-id/flat/1456154321.976561.528310154.6A623C0E%40webmail.messagingengine.com https://www.postgresql.org/message-id/flat/CA%2BwPC0MRMhF_8fD9dc8%2BQWZQzUvHahPRSv%3DxMtCmsVLSsy-p0w%40mail.gmail.com I've made a synthetic test, which kind of reproduces the issue: shared_buffers = 512MB effective_cache_size = 512MB work_mem = 100MB set seq_page_cost = 1.0; set random_page_cost = 1.5; set cpu_tuple_cost = 0.01; set cpu_index_tuple_cost = 0.005; set cpu_operator_cost = 0.0025; 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 I've been running the same query while enabling and disabling different kinds of scans: 1) set enable_bitmapscan = on;  set enable_indexscan = off; set enable_seqscan = off; 2) set enable_bitmapscan = off; set enable_indexscan = on;  set enable_seqscan = off; 3) set enable_bitmapscan = off; set enable_indexscan = off; set enable_seqscan = on; The query was: explain (analyze,verbose,costs,buffers) select count(*) from aaa where num = 1 and flag = true; Here are the results for PostgreSQL 9.6 (for 9.3 and 10.1 the results are very similar): 1) Aggregate  (cost=24821.70..24821.71 rows=1 width=8) (actual time=184.591..184.591 rows=1 loops=1)   Output: count(*)   Buffers: shared hit=47259   ->  Bitmap Heap Scan on public.aaa  (cost=13038.21..24796.22 rows=10189 width=0) (actual time=122.492..178.006 rows=100000 loops=1)         Output: num, flag         Recheck Cond: (aaa.num = 1)         Filter: aaa.flag         Heap Blocks: exact=44248         Buffers: shared hit=47259         ->  BitmapAnd  (cost=13038.21..13038.21 rows=10189 width=0) (actual time=110.699..110.699 rows=0 loops=1)               Buffers: shared hit=3011               ->  Bitmap Index Scan on i1  (cost=0.00..1158.94 rows=99667 width=0) (actual time=19.600..19.600 rows=100000 loops=1)                     Index Cond: (aaa.num = 1)                     Buffers: shared hit=276               ->  Bitmap Index Scan on i2  (cost=0.00..11873.92 rows=1022332 width=0) (actual time=81.676..81.676 rows=1000000 loops=1)                     Index Cond: (aaa.flag = true)                     Buffers: shared hit=2735 Planning time: 0.104 ms Execution time: 184.988 ms 2) Aggregate  (cost=67939.09..67939.10 rows=1 width=8) (actual time=67.510..67.510 rows=1 loops=1)   Output: count(*)   Buffers: shared hit=44524   ->  Index Scan using i1 on public.aaa  (cost=0.44..67910.95 rows=11256 width=0) (actual time=0.020..61.180 rows=100000 loops=1)         Output: num, flag         Index Cond: (aaa.num = 1)         Filter: aaa.flag         Buffers: shared hit=44524 Planning time: 0.096 ms Execution time: 67.543 ms 3) Aggregate  (cost=169276.49..169276.50 rows=1 width=8) (actual time=977.063..977.063 rows=1 loops=1)   Output: count(*)   Buffers: shared hit=44248   ->  Seq Scan on public.aaa  (cost=0.00..169248.35 rows=11256 width=0) (actual time=0.018..969.294 rows=100000 loops=1)         Output: num, flag         Filter: (aaa.flag AND (aaa.num = 1))         Rows Removed by Filter: 9900000         Buffers: shared hit=44248 Planning time: 0.099 ms Execution time: 977.094 ms The bitmap scan version runs more than twice slower than the one with index scan, while being costed at more than twice cheaper. I've tried to increase cpu_tuple_cost and cpu_index_tuple_cost, and this behavior remains after 6x increase in values. Although the difference in costs becomes much less. After increasing the settings more than 6x, PostgreSQL decides to use a different plan for bitmap scans, so it's hard to make conclusions at that point. Could such cases be fixed with tuning of cost settings, or that's just how PostgreSQL estimates bitmap scans and this can't be fixed without modifying the optimizer? Or am I missing something and that's the expected behavior? Thoughts? Regards, Vitaliy