PostgreSQL NULL值相对位置与QUERY优化 - nulls first\last, asc\desc

标签

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、改进索引扫描方法,支持环形扫描。

时间: 2024-12-02 08:47:54

PostgreSQL NULL值相对位置与QUERY优化 - nulls first\last, asc\desc的相关文章

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

标签 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;

Oracle数据库中对null值的排序及mull与空字符串的区别_oracle

order by排序之null值处理方法在对业务数据排序时候,发现有些字段的记录是null值,这时排序便出现了有违我们使用习惯的数据大小顺序问题.在Oracle中规定,在Order by排序时缺省认为null是最大值,所以如果是ASC升序则被排在最后,而DESC降序则排在最前.所以,为何分析数据的直观性方便性,我们需要对null的记录值进行相应处理. 这是四种oracle排序中NULL值处理的方法:1.使用nvl函数语法:Nvl(expr1, expr2)     若EXPR1是NULL,則返回

oracle使用order by排序null值如何处理_oracle

适用情况: oracle 对查询结果进行排序时,被排序的栏位存在null值,且要指定NULL值排在最前面或者最后面 关键字:Nulls First:Nulls Last 默认情况:null 默认为最大值(即:asc 升序<小-->大>,null值排在最后:desc 降序<大-->小>,null值排在最前面) 指定: 1.Oracle Order by支持的语法 2.指定Nulls first 则表示null值的记录将排在最前(不管是asc 还是desc) 3.指定Nul

MySQL · 专家投稿 · InnoDB物理行中null值的存储的推断与验证

前言 想写这边文章,是因为之前想写一个解析innodb ibd文件的工具,在写这个工具的过程中,发现逻辑记录转物理记录的转换中,最难的有两部分,一是每行每字段null值占用的字节和存储,二是变长字段占用的字节和存储的格式.本文中重点针对第一种情况. 之前看有关介绍compact行记录格式: 变长字段之后的第二个部分是NULL标志位,该位指示了该行数据中是否有NULL值,有则用1表示.该部分所占字节为1字节 -–<InnoDB存储引擎> 之后便思考是否不管有多少个列都是NULL,该部分都只占1个

android-getLastknownLocation()在 nexus 返回null值

问题描述 getLastknownLocation()在 nexus 返回null值 我使用下面的代码来开发一个基于位置定位的项目,这个项目我是用的是google api 8. lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this); currloc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER); TextView t = (TextView)find

【MYSQL数据库开发之四】MYSQL NULL值操作、批处理模式、常用查询的例子、计数行、模式匹配等

本站文章均为 李华明Himi 原创,转载务必在明显处注明:  转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/mysql/781.html 继续上一篇继续讲解MySQL的相关知识点:      1. NULL 值操作: NULL值可能令人感到奇怪直到你习惯它.概念上,NULL意味着"没有值"或"未知值",且它被看作与众不同的值.为了测试NULL,你不能使用算术比较 操作符例如=.<或!=.为了说明它,试试下列查询:

NULL 值与索引(一)

    NULL值是关系数据库系统布尔型(true,false,unknown)中比较特殊类型的一种值,通常称为UNKNOWN或空值,即是未知的,不确定的.由于NULL存在着无数的可能,因此NULL值也不等于NULL值,所以与NULL值相关的操作同样都为NULL值.正是基于这样一个特性,对于NULL值列上的B树索引导致了is null/is not null不走索引的情形,下面描述了NULL值与索引以及索引NULL列上的执行计划,如何使得NULL值走索引的情形.注:本文仅仅讨论的是B树索引上的N

MySQL查询NULL值处理函数详解

我们已经看到使用WHERE子句的SQL SELECT命令来从MySQL表获取数据.但是,当我们试图给的条件比较字段或列的值为NULL,它不能正常工作. 为了处理这种情况,MySQL提供了三大运算符 IS NULL: 此运算符返回true,当列的值是NULL. IS NOT NULL: 运算符返回true,当列的值不是NULL. <=> 操作符比较值(不同于=运算符)为ture,即使两个NULL值 涉及NULL条件是特殊的.不能使用 =NULL 或 !=NULL 寻找NULL值的列.这种比较总是

NULL 值与索引

 NULL 值与索引     NULL值是关系数据库系统布尔型(true,false,unknown)中比较特殊类型的一种值,通常称为UNKNOWN或空值,即是未知的,不确定的.由于 NULL存在着无数的可能,因此NULL值也不等于NULL值,所以与NULL值相关的操作同样都为NULL值.正是基于这样一个特性,对于NULL值列上的B 树索引导致了is null/is not null不走索引的情形,下面描述了NULL值与索引以及索引NULL列上的执行计划,如何使得NULL值走索引的情形. 注:本