Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtp (Exim 4.80) (envelope-from ) id 1Xm8Ls-0003yk-RY for pgsql-performance@arkaria.postgresql.org; Wed, 05 Nov 2014 21:42:52 +0000 Received: from localhost ([127.0.0.1] helo=postgresql.org) by malur.postgresql.org with smtp (Exim 4.80) (envelope-from ) id 1Xm8Ls-0006GP-A6 for pgsql-performance@arkaria.postgresql.org; Wed, 05 Nov 2014 21:42:52 +0000 Received: from makus.postgresql.org ([2001:4800:1501:1::229]) by malur.postgresql.org with esmtps (TLS1.2:DHE_RSA_AES_256_CBC_SHA256:256) (Exim 4.80) (envelope-from ) id 1Xm8Lr-0006E4-2v for pgsql-performance@postgresql.org; Wed, 05 Nov 2014 21:42:51 +0000 Received: from mail-wg0-x231.google.com ([2a00:1450:400c:c00::231]) by makus.postgresql.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:256) (Exim 4.80) (envelope-from ) id 1Xm8Ln-0002I4-PR for pgsql-performance@postgresql.org; Wed, 05 Nov 2014 21:42:49 +0000 Received: by mail-wg0-f49.google.com with SMTP id x13so1943374wgg.8 for ; Wed, 05 Nov 2014 13:42:44 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=date:from:to:subject:message-id:mime-version:content-type :content-disposition:content-transfer-encoding:user-agent; bh=+RgaMBil3pO5g0B50quX/n77IQJevgIGD4/iZV01mro=; b=Q907t80D+h36FLn5kcvY8q/adROaJW6euBIggVHI3XWBlkjmdVpPzIzr5m2G6w5jLD IQhoMj91Du4WDr0ucbC8MjqQVSmgHidJ0GsbAZlQ8+H92i2FCWc3CFxDbNPNHrAJTgsc OP4oXsIBBYCrYuEIv1YELVKTR7MIDpmD1+o+DP3UjtUIx5s4ADAV57Qkh1Md6fr3h6AG 7no/2fzjJT4mmsShL3AC/wH+2XO0kAnx/G57F5p+qrs3R8FFxW2zPjgRZj3BEXEsK8sh d+mFTTbdCbrRxIIDLvsl2s9Ioje7q2Q4TU0QIhpaR4y3m0ZIUZZvHVnksbOr1lhNP5s4 lF/A== X-Received: by 10.180.107.35 with SMTP id gz3mr19833579wib.38.1415223764860; Wed, 05 Nov 2014 13:42:44 -0800 (PST) Received: from public-docking-cx-1771.ethz.ch (public-docking-pat-cx-mapped-0015.ethz.ch. [195.176.111.16]) by mx.google.com with ESMTPSA id vq1sm5473339wjc.29.2014.11.05.13.42.44 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 05 Nov 2014 13:42:44 -0800 (PST) Date: Wed, 5 Nov 2014 22:42:43 +0100 From: =?utf-8?Q?Art=C5=ABras?= Lapinskas To: postgres performance list Subject: Index order ignored after `is null` in query Message-ID: <20141105214243.GA546@public-docking-cx-1771.ethz.ch> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8; format=flowed Content-Disposition: inline Content-Transfer-Encoding: 8bit User-Agent: Mutt/1.5.23 (2014-03-12) X-Pg-Spam-Score: -2.7 (--) List-Archive: List-Help: List-ID: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: X-Mailing-List: pgsql-performance Precedence: bulk Sender: pgsql-performance-owner@postgresql.org Hello, I am having some hard time understanding how postgresql handles null values. As much I understand null values are stored in b-tree as simple values (put as last or first depending on index). But it seems that there is something really specific about them as postgresql deliberately ignores obvious (I think...) optimizations concerning index order after using one of them in a query. As a simple example look at table below: arturas=# drop table if exists test; DROP TABLE arturas=# create table test ( arturas(# a int not null, arturas(# b int, arturas(# c int not null arturas(# ); CREATE TABLE After filling this table with random data (actual distribution of null's/real values seams not to matter): arturas=# insert into test (a, b, c) arturas-# select arturas-# case when random() < 0.5 then 1 else 2 end arturas-# , case when random() < 0.5 then null else 1 end arturas-# , case when random() < 0.5 then 1 else 2 end arturas-# from generate_series(1, 1000000, 1) as gen; INSERT 0 1000000 And creating index: arturas=# create index test_idx on test (a, b nulls first, c); CREATE INDEX We get fast queries with `order by` on c: arturas=# explain analyze verbose select * from test where a = 1 and b = 1 order by c limit 1; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------- Limit (cost=0.42..0.53 rows=1 width=12) (actual time=0.052..0.052 rows=1 loops=1) Output: a, b, c -> Index Only Scan using test_idx on public.test (cost=0.42..25890.42 rows=251433 width=12) (actual time=0.051..0.051 rows=1 loops=1) Output: a, b, c Index Cond: ((test.a = 1) AND (test.b = 1)) Heap Fetches: 1 Total runtime: 0.084 ms (7 rows) But really slow ones if we search for null values of b: arturas=# explain analyze verbose select * from test where a = 1 and b is null order by c limit 1; QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------- Limit (cost=15632.47..15632.47 rows=1 width=12) (actual time=138.127..138.127 rows=1 loops=1) Output: a, b, c -> Sort (cost=15632.47..16253.55 rows=248434 width=12) (actual time=138.127..138.127 rows=1 loops=1) Output: a, b, c Sort Key: test.c Sort Method: top-N heapsort Memory: 25kB -> Bitmap Heap Scan on public.test (cost=6378.87..14390.30 rows=248434 width=12) (actual time=47.083..88.986 rows=249243 loops=1) Output: a, b, c Recheck Cond: ((test.a = 1) AND (test.b IS NULL)) -> Bitmap Index Scan on test_idx (cost=0.00..6316.77 rows=248434 width=0) (actual time=46.015..46.015 rows=249243 loops=1) Index Cond: ((test.a = 1) AND (test.b IS NULL)) Total runtime: 138.200 ms (12 rows) Can someone please give some insight on this problem :) P.S. I am using `select version()` => PostgreSQL 9.3.5 on x86_64-unknown-linux-gnu, compiled by gcc (Debian 4.7.2-5) 4.7.2, 64-bit, compiled from source with no default configuration changes. -- Best Regard, Artūras Lapinskas -- Sent via pgsql-performance mailing list (pgsql-performance@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-performance