Postgresql null值判断,排序,以及排序后对索引的影响

时间:2021-12-27 04:43:34
首先null值不会分配空间,这一点与''是本质区别,但是表现形式是一样的
首先null值与任何值做布尔运算,结果都是false


null值判断,is null,is not null
hank=> create table tab1 (a int ,b varchar(20));
CREATE TABLE
hank=> insert into tab1 values(1,'hank');
INSERT 0 1
hank=> insert into tab1 values(1,null);  
INSERT 0 1
hank=> insert into tab1 values(1,'askasdjk');
INSERT 0 1
hank=> select * from tab1 where b <>'hank';
 a |    b     
---+----------
 1 | askasdjk
(1 row)
可见b为null的值是不被筛选的
hank=> insert into tab1 values(1,'');        
INSERT 0 1
hank=> select * from tab1 where b <>'hank';  
 a |    b     
---+----------
 1 | askasdjk
 1 | 
 ''是可以被筛选的
要想达到效果,可以用如下写法
select * from tab1 where b <>'hank' or b is null;
 a |    b     
---+----------
 1 | 
 1 | askasdjk
 1 | 
(3 rows)
hank=> select * from tab1 where coalesce(b,'0')<>'hank';
 a |    b     
---+----------
 1 | 
 1 | askasdjk
 1 | 
(3 rows)




null值排序
hank=>  select ctid,* from tab1 where b <>'hank' or b is null order by b nulls first;
 ctid  | a |    b     
-------+---+----------
 (0,2) | 1 | 
 (0,4) | 1 | 
 (0,3) | 1 | askasdjk
 hank=> select ctid,* from tab1 where b <>'hank' or b is null order by b nulls last; 
 ctid  | a |    b     
-------+---+----------
 (0,4) | 1 | 
 (0,3) | 1 | askasdjk
 (0,2) | 1 | 
(3 rows)




null值排序对索引的影响
null列索引注意一定要一致,否则索引用不到
insert into tab1 select generate_series(1,1000),'hank'||generate_series(1,1000);
hank=> create index idx_tab1_b on tab1(b nulls first);
hank=> explain select * from tab1  order by b limit 1; 
                             QUERY PLAN                              
---------------------------------------------------------------------
 Limit  (cost=21.06..21.06 rows=1 width=11)
   ->  Sort  (cost=21.06..23.57 rows=1004 width=11)
         Sort Key: b
         ->  Seq Scan on tab1  (cost=0.00..16.04 rows=1004 width=11)
(4 rows)


hank=> explain select * from tab1  order by b nulls first limit 1;    
                                    QUERY PLAN                                    
----------------------------------------------------------------------------------
 Limit  (cost=0.28..0.32 rows=1 width=11)
   ->  Index Scan using idx_tab1_b on tab1  (cost=0.28..49.21 rows=1004 width=11)


hank=> explain select * from tab1  order by b nulls last limit 1;     
                             QUERY PLAN                              
---------------------------------------------------------------------
 Limit  (cost=21.06..21.06 rows=1 width=11)
   ->  Sort  (cost=21.06..23.57 rows=1004 width=11)
         Sort Key: b
         ->  Seq Scan on tab1  (cost=0.00..16.04 rows=1004 width=11)
(4 rows)


可见,null值得先后可以决定索引是否可以用到idx_tab1_b这个索引,需要重新排序




hank=> create index idx_tab1_b_1 on tab1(b);    
CREATE INDEX
hank=>  explain select * from tab1 order by b;
                                  QUERY PLAN                                  
------------------------------------------------------------------------------
 Index Scan using idx_tab1_b_1 on tab1  (cost=0.28..49.21 rows=1004 width=11)
(1 row)


hank=>  explain select * from tab1 order by b desc;
                                      QUERY PLAN                                       
---------------------------------------------------------------------------------------
 Index Scan Backward using idx_tab1_b_1 on tab1  (cost=0.28..49.21 rows=1004 width=11)
(1 row)


hank=>  explain select * from tab1 order by b asc; 
                                  QUERY PLAN                                  
------------------------------------------------------------------------------
 Index Scan using idx_tab1_b_1 on tab1  (cost=0.28..49.21 rows=1004 width=11)
(1 row)
不涉及null值排序的索引不会出现此种情况
所以有空值的字段如果对null值有排序需求,那么建索引的时候一定要按筛选条件建立。