PostgreSQL 数据库NULL值的默认排序行为与查询、索引定义规范 - nulls first\last, asc\desc...
背景
在数据库中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、改进索引扫描方法,支持环形扫描。
参考:
https://github.com/digoal/blog/blob/master/201711/20171111_02.md
注:
- 如果创建索引时,没有指定null的内容,但where条件部分又使用到了null的排序,那么要将asc|desc 与 last|first对应好,默认对应的操作是:
desc nulls first : null large small asc nulls last : small large null
在没有指定null的索引中,按照上面方法对应好即可。
下面是几个测试:
swrd=# \d ccTable "swrd.cc"Column | Type | Modifiers
--------+---------+-----------id | integer | not null Indexes: "cc_id_idx" btree (id) swrd=# explain (analyze,verbose,timing,costs,buffers) select * from cc order by id desc nulls first; QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------- Index Only Scan Backward using cc_id_idx on swrd.cc (cost=0.42..30408.42 rows=1000000 width=4) (actual time=0.044..297.796 rows=1000000 loops=1) Output: id Heap Fetches: 1000000 Buffers: shared hit=7159 read=1 Planning time: 0.113 ms Execution time: 387.645 ms (6 rows) Time: 388.438 ms swrd=# explain (analyze,verbose,timing,costs,buffers) select * from cc order by id desc nulls last; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------- Sort (cost=127757.34..130257.34 rows=1000000 width=4) (actual time=666.996..926.348 rows=1000000 loops=1) Output: id Sort Key: cc.id DESC NULLS LAST Sort Method: external merge Disk: 13640kB Buffers: shared hit=4425, temp read=2334 written=2334 -> Seq Scan on swrd.cc (cost=0.00..14425.00 rows=1000000 width=4) (actual time=0.020..147.384 rows=1000000 loops=1) Output: id Buffers: shared hit=4425 Planning time: 0.110 ms Execution time: 1027.649 ms (10 rows)
会发现默认使用没有配置null的索引,但是在where条件中使用到了null,如果不是按照默认的对应顺序使用,则数据库会额外排序,无法使用到索引本身的排序功能。
- 而对于在创建索引时,指定了null选项,则在where条件中和索引指定的null一致即可。
转载于:https://www.cnblogs.com/telwanggs/p/10762042.html
PostgreSQL 数据库NULL值的默认排序行为与查询、索引定义规范 - nulls first\last, asc\desc...相关推荐
- golang 数据库null值错误 解决方法
遇到问题: converting NULL to string is unsupported 定义的结构体中 结构体成员类型为string,从mysql数据库中查询数据中有NULL值,go语言执行sc ...
- 数据库-null值处理及元数据
MySQL NULL 值处理 我们已经知道 MySQL 使用 SQL SELECT 命令及 WHERE 子句来读取数据表中的数据,但是当提供的查询条 件字段为 NULL 时,该命令可能就无法正常工作. ...
- ASP——判断数据库NULL值
有一个表test1,有字段num,字段num有null值,也有空值,也有其他值,我要用asp语句判断我查询出来的num的值是否为null值. 严谨一点,要有两层判断: If IsNull(Rs(&qu ...
- 数据库-null值和notnull操作
null和not null值 对一些字段类型要进行检查,判断某些字段是否为NULL,或者 non-NULL mysql> SELECT name, birth, death, ‐> TIM ...
- [随笔] 数据库NULL值的含义及陷阱
文章内容仅为自己网课学习内容记录,截图来自于天善学院,BAO胖子的免费网课视频 网课视频地址: https://edu.hellobi.com/course/54 NULL 的含义 Null 不代表0 ...
- mysq对存在null值的字段排序
1.建立学生表,建表sql如下: create table student(id int,name varchar(20),age int); 2.插入几条数据,包括id字段值为null的 inser ...
- oracle和mysql空字符串_Oracle数据库中对null值的排序及mull与空字符串的区别
order by排序之null值处理方法在对业务数据排序时候,发现有些字段的记录是null值,这时排序便出现了有违我们使用习惯的数据大小顺序问题.在Oracle中规定,在Order by排序时缺省认为 ...
- oracle根据null排序,oracle 关于null值排序
在oracle中根据字段来desc排序的话null值可能会在数据的最前面.然而有时候我们查看数据的时候并不希望能够在前面看到这些null值的排序数据. 因此我查了一下: 1.排序的时候运用nvl(). ...
- 下列有关mysql数据库中的null值_MySQL数据库中与 NULL值有关的问题
对于SQL的新手,NULL值的概念常常会造成混淆,他们常认为NULL是与空字符串"相同的事.情况并非如此.例如,下述语句是完全不同的: mysql> INSERT INTO my_ta ...
最新文章
- idea中刷新项目快捷键_解决 IDEA 使用过程中让你觉得不爽的一些问题
- 初窥Go module
- 史上最全的Linux常用——目录和文件管理命令——收藏这一篇就够了!(超全,超详细)
- json数据格式化展示出来
- linux执行脚本n,Linux执行sh脚本空白
- android自定义队列,Android 消息机制(一)消息队列的创建与循环的开始 Looper与MessageQueue...
- 分支定界 matlab,分支定界法matlab程序
- [量子计算]量子计算的发展史与中国现在的量子计算整体水平
- C4D建模宝典R20笔记
- Echarts.js下载及简易Demo
- 跨站请求伪造(CSRF)漏洞简介及靶场演示
- XML解析—开源XOM类库
- VirtualApp hook so及activity回调
- linux dolphin模拟器,Dolphin for Mac(GameCube模拟器)
- 为什么Google要将LiveData设计成粘性的
- centeros 卸载mysql_如何卸载数据库centeros
- 自动修改hosts文件
- linux+显卡驱动下载官网下载地址,下载:NVIDIA显卡Linux驱动256.44正式版
- 右键计算机没有软件删减,右键菜单太长会导致电脑卡顿?轻松删除右键菜单无用项!...
- 哈工大深圳计算机就业质量报告,多所高校公布毕业生平均年薪,南京大学和哈工大(深圳)数据亮眼...
热门文章
- html table的边框线怎么变圆角_实现CSS3中的border-radius(边框圆角)示例代码
- axios 超时_聊聊 Vue 中 axios 的封装
- 服务器显示转速负数,Moldflow使用常见问题及解决方案
- (147)FPGA面试题-Verilog移位相加实现乘法(二)
- (90)FPGA仿真计数器激励
- (62)Verilog HDL模块例化system Verilog模块
- lamp 重启mysql_lamp常用命令 --Ubuntu下启动/重启/停止apache,mysql服务器
- boost 获取时间
- boost 获取日期时间
- java flink项目_IDEA上运行Flink任务的实战教程