PostgreSQL 数据库NULL值的默认排序行为与查询、索引定义规范 - nulls first\last, asc\desc

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云数据库 RDS SQL Server,独享型 2核4GB
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介:

标签

PostgreSQL , NULLS FIRST , NULLS LAST , ASC , DESC , 默认行为 , sort


背景

在数据库中NULL值是指UNKNOWN的值,不存储任何值,在排序时,它排在有值的行前面还是后面通过语法来指定。

例如

-- 表示null排在有值行的前面  
select * from tbl order by id nulls first;  
  
-- 表示null排在有值行的后面  
select * from tbl order by id nulls last;  

同时对于有值行,可以指定顺序排还是倒序排。

-- 表示按ID列顺序排  
select * from tbl order by id [asc];  
  
-- 表示按ID列倒序排  
select * from tbl order by id desc;  

默认的排序规则如下:

desc nulls first : null large small    
  
asc nulls last : small large null    

当nulls [first|last]与asc|desc组合起来用时,是这样的。

值的顺序如下:

1、DEFAULT:(认为NULL比任意值都大)

desc nulls first : 顺序:null large small    
  
asc nulls last   : 顺序:small large null    

2、NON DEFAULT: (认为NULL比任意值都小)

desc nulls last : 顺序:large small null       
  
asc nulls first : 顺序:null small large       

由于索引是固定的,当输入排序条件时,如果排序条件与索引的排序规则不匹配时,会导致无法使用索引的实惠(顺序扫描)。导致一些不必要的麻烦。

索引定义与扫描定义不一致引发的问题

1、建表,输入测试数据

create table cc(id int not null);  
  
insert into cc select generate_series(1,1000000);  

2、建立索引(使用非默认配置,null比任意值小)

create index idx_cc on cc (id asc nulls first);  
  
或  
  
create index idx_cc on cc (id desc nulls last);  

3、查询,与索引定义的顺序(指NULL的相对位置)不一致时,即使使用索引,也需要重新SORT。

select * from table order by id desc nulls first limit 1;   
select * from table order by id [asc] nulls last limit 1;   

用到了额外的SORT

postgres=# explain (analyze,verbose,timing,costs,buffers) select * from cc order by id limit 1;  
                                                                 QUERY PLAN                                                                    
---------------------------------------------------------------------------------------------------------------------------------------------  
 Limit  (cost=27969.43..27969.43 rows=1 width=4) (actual time=263.972..263.972 rows=1 loops=1)  
   Output: id  
   Buffers: shared hit=7160  
   ->  Sort  (cost=27969.43..30469.43 rows=1000000 width=4) (actual time=263.970..263.970 rows=1 loops=1)  
         Output: id  
         Sort Key: cc.id  
         Sort Method: top-N heapsort  Memory: 25kB  
         Buffers: shared hit=7160  
         ->  Bitmap Heap Scan on public.cc  (cost=8544.42..22969.42 rows=1000000 width=4) (actual time=29.927..148.733 rows=1000000 loops=1)  
               Output: id  
               Heap Blocks: exact=4425  
               Buffers: shared hit=7160  
               ->  Bitmap Index Scan on idx_cc  (cost=0.00..8294.42 rows=1000000 width=0) (actual time=29.380..29.380 rows=1000000 loops=1)  
                     Buffers: shared hit=2735  
 Planning time: 0.098 ms  
 Execution time: 264.009 ms  
(16 rows)  

3、查询,与索引定义一致(指NULL的相对位置)时,索引有效,不需要额外SORT。

select * from table order by id desc nulls last limit 1;   
select * from table order by id [asc] nulls first limit 1;   

不需要额外SORT

postgres=# explain (analyze,verbose,timing,costs,buffers) select * from cc order by id nulls first limit 1;  
                                                              QUERY PLAN                                                                 
---------------------------------------------------------------------------------------------------------------------------------------  
 Limit  (cost=0.42..0.45 rows=1 width=4) (actual time=0.014..0.014 rows=1 loops=1)  
   Output: id  
   Buffers: shared hit=4  
   ->  Index Only Scan using idx_cc on public.cc  (cost=0.42..22719.62 rows=1000000 width=4) (actual time=0.013..0.013 rows=1 loops=1)  
         Output: id  
         Heap Fetches: 1  
         Buffers: shared hit=4  
 Planning time: 0.026 ms  
 Execution time: 0.022 ms  
(9 rows)  

小结

在PostgreSQL中顺序、倒序索引是通用的。不同的是null的相对位置。

因此在创建索引时,务必与业务的需求对齐,使用一致的NULL相对顺序(nulls first 或 nulls last 与asc,desc的搭配)(即NULL挨着large value还是small value),而至于值的asc, desc实际上是无所谓的。 

如果业务需求的顺序与索引的顺序不一致(指null的相对顺序),那么会导致索引需要全扫,重新SORT的问题。

内核改进

1、当约束设置了not null时,应该可以不care null的相对位置,因为都没有NULL值了,优化器应该可以不管NULL的相对位置是否与业务请求的SQL的一致性,都选择非Sort模式扫描。

2、改进索引扫描方法,支持环形扫描。

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
15天前
|
关系型数据库 分布式数据库 数据库
PolarDB for PostgreSQL报错问题之psql连接数据库报错如何解决
PolarDB for PostgreSQL是基于PostgreSQL开发的一款云原生关系型数据库服务,它提供了高性能、高可用性和弹性扩展的特性;本合集将围绕PolarDB(pg)的部署、管理和优化提供指导,以及常见问题的排查和解决办法。
|
24天前
|
关系型数据库 MySQL 数据处理
MySQL vs. PostgreSQL:选择适合你的开源数据库
在当今信息时代,开源数据库成为许多企业和开发者的首选。本文将比较两个主流的开源数据库——MySQL和PostgreSQL,分析它们的特点、优势和适用场景,以帮助读者做出明智的选择。
|
26天前
|
关系型数据库 PostgreSQL
PostgreSQL排序字段不唯一导致分页查询结果出现重复数据
PostgreSQL排序字段不唯一导致分页查询结果出现重复数据
18 0
|
30天前
|
关系型数据库 测试技术 数据库
`pg_rewind` 是 PostgreSQL 数据库的一个工具,用于将一个数据库集群回退到指定的时间点
pg_rewind 是 PostgreSQL 数据库的一个工具,用于将一个数据库集群回退到指定的时间点。这对于恢复数据或解决某些问题非常有用。 简单来说,如果你有一个 PostgreSQL 数据库集群并且你知道在某个时间点它是健康的,但之后出现了问题,你可以使用 pg_rewind 来将数据库回退到那个时间点,从而恢复到已知的、健康的、一致的状态。 使用 pg_rewind 的基本步骤如下: 确定基准时间:首先,你需要确定一个基准时间点,知道在该时间点上数据库是健康的。 备份当前数据库:在执行 pg_rewind 之前,确保你已经备份了当前的数据库。 执行 pg_rewind:使用
|
1月前
|
关系型数据库 C# 数据库
2023 年度数据库 PostgreSQL 遇到年度编程语言 C# 会发生什么样的火花?
2023 年度数据库 PostgreSQL 遇到年度编程语言 C# 会发生什么样的火花?分析这俩的发展趋势,技术生态,社区活跃度,特别是国产化信创领域的支持度?
41 1
|
1月前
|
关系型数据库 数据库 PostgreSQL
PostgreSQL从入门到精通 - 第40讲:数据库不完全恢复
PostgreSQL从入门到精通 - 第40讲:数据库不完全恢复
116 1
|
2月前
|
SQL 关系型数据库 数据库
postgresql数据库修改参数的方式
在PostgreSQL数据库中,你可以通过多种方式修改数据库参数,以更改其行为。以下是一些常见的修改数据库参数的方式: 1. **通过配置文件修改(postgresql.conf):** PostgreSQL的配置文件是 `postgresql.conf`。你可以直接编辑该文件,找到要修改的参数,修改其值,然后重新启动PostgreSQL服务以使更改生效。 通常,`postgresql.conf` 文件位于 PostgreSQL 数据目录下。修改完毕后,确保重新启动 PostgreSQL 服务。 2. **使用 ALTER SYSTEM 命令:** PostgreSQL
|
2月前
|
SQL 关系型数据库 MySQL
MySQL【实践 02】MySQL迁移到PostgreSQL数据库的语法调整说明及脚本分享(通过bat命令修改mapper文件内的SQL语法)
MySQL【实践 02】MySQL迁移到PostgreSQL数据库的语法调整说明及脚本分享(通过bat命令修改mapper文件内的SQL语法)
47 0
|
2月前
|
关系型数据库 数据库 PostgreSQL
Docker【应用 03】给Docker部署的PostgreSQL数据库安装PostGIS插件(安装流程及问题说明)
Docker【应用 03】给Docker部署的PostgreSQL数据库安装PostGIS插件(安装流程及问题说明)
68 0
|
2月前
|
SQL JSON Java
Java【问题记录 02】对象封装+固定排序+list All elements are null引起的异常处理+Missing artifact com.sun:tools:jar:1.8.0
Java【问题记录 02】对象封装+固定排序+list All elements are null引起的异常处理+Missing artifact com.sun:tools:jar:1.8.0
35 0

相关产品

  • 云原生数据库 PolarDB