暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

移动云HaishanDB和MySQL中 NULL 排序行为差异解析

原创 移动云He3DB 2026-05-22
50

1、摘要

在数据库兼容性开发过程中,NULL 的排序规则是一个容易被忽视但非常关键的问题。当海山PG在实现 MySQL 兼容时,如果不处理 NULL 排序行为,很多 SQL 的执行结果会与 MySQL 不一致,从而导致应用兼容性问题。

本文从行为差异、实现原理、海山PG的内核机制以及索引排序关系等多个角度,系统分析 海山PG与 MySQL 在 NULL 排序方面的差异,并给出在实现 MySQL 兼容数据库时的工程实践方案。

2、NULL 的基本语义

在SQL标准中,NULL表示“未知值(unknown)”,而不是0或空字符串。

NULL具有两个重要特性:

1)NULL不参与普通比较

NULL = NULL → NULL

NULL < 1 → NULL

2)NULL只能通过IS NULL或IS NOT NULL判断

col IS NULL

col IS NOT NULL

SQL标准并没有严格规定NULL在排序中的默认位置,因此不同数据库实现可能存在差异。

3、NULL排序差异

假设有如下测试表:

CREATE TABLE t(id int);

INSERT INTO t VALUES (1),(2),(NULL),(3);

3.1 MySQL默认排序行为

执行以下SQL:

SELECT * FROM t ORDER BY id ASC;

结果:

NULL

1

2

3

执行以下SQL:

SELECT * FROM t ORDER BY id DESC;

结果:

3

2

1

NULL

结论:

MySQL规则

ASC → NULL FIRST

DESC → NULL LAST

MySQL实际上将NULL视为最小值。

3.2 海山PG默认排序行为

执行以下SQL:

SELECT * FROM t ORDER BY id ASC;

结果:

1

2

3

NULL

执行以下SQL:

SELECT * FROM t ORDER BY id DESC;

结果:

NULL

3

2

1

海山PG规则:

ASC → NULL LAST

DESC → NULL FIRST

海山PG将NULL视为最大值。

4、SQL标准中的NULL排序控制

SQL标准允许显式指定NULL排序位置:

ORDER BY column NULLS FIRST

ORDER BY column NULLS LAST

例如:

SELECT * FROM t ORDER BY id ASC NULLS FIRST;

SELECT * FROM t ORDER BY id DESC NULLS LAST;

海山PG完整支持该语法,而MySQL不支持NULLS FIRST / LAST语法。

5、海山PG与MySQL不同的原因

两者差异主要来自数据库内部比较逻辑的不同。

MySQL比较逻辑:

NULL < ANY NON-NULL VALUE

因此:

ASC → NULL FIRST

DESC → NULL LAST

海山PG比较逻辑:

NULL > ANY NON-NULL VALUE

因此:

ASC → NULL LAST

DESC → NULL FIRST

也就是说,MySQL将NULL视为“无限小”;海山PG将NULL视为“无限大”。

6、海山PG中ORDER BY排序实现

海山PG中ORDER BY排序主要由tuplesort模块完成。

执行流程:

Executor

ExecSort

tuplesort_begin_xxx()

tuplesort_puttupleslot()

tuplesort_performsort()

排序过程中真正决定排序顺序的是SortSupport comparator。

海山PG使用SortSupport结构控制排序行为:

typedef struct SortSupportData

{

bool ssup_reverse;

bool ssup_nulls_first;

int (*comparator) (Datum x, Datum y, SortSupport ssup);

} SortSupportData;

NULL比较逻辑示意:

if (isNull1 && isNull2)

return 0;

if (isNull1)

return ssup_nulls_first ? -1 : 1;

if (isNull2)

return ssup_nulls_first ? 1 : -1;

真正控制NULL位置的是ssup_nulls_first参数。

7、海山PG默认NULL排序规则

当SQL未指定NULLS FIRST / LAST时,海山PG会自动推导:

ASC → NULLS LAST

DESC → NULLS FIRST

因此:

ORDER BY col ASC

等价于

ORDER BY col ASC NULLS LAST

ORDER BY col DESC

等价于

ORDER BY col DESC NULLS FIRST

8、索引扫描与NULL排序的关系

NULL排序不仅影响结果顺序,还影响是否能够使用索引避免排序。

示例:

CREATE INDEX idx_age ON user(age);

EXPLAIN

SELECT * FROM user ORDER BY age;

如果排序顺序与索引一致,执行计划可能为:

Index Scan using idx_age

否则可能需要:

Seq Scan

Sort

海山PG的BTree 索引规定:

NULLS ARE LARGER THAN ANY VALUE

因此:

ASC → NULL LAST

DESC → NULL FIRST

这与海山PG的默认排序规则保持一致,从而能够直接利用索引顺序。

假设为了兼容 MySQL,将海山PG修改为:

NULL < ANY VALUE

那么排序规则会变为:

ASC → NULL FIRST

DESC → NULL LAST

此时 BTree 索引顺序将与排序规则不一致,很多 ORDER BY 查询将无法直接利用索引,必须额外执行 Sort 操作,导致性能下降。

9、总结

海山PG与MySQL在NULL排序行为上的差异源于其内部比较逻辑不同:

MySQL:NULL < ANY VALUE

海山PG:NULL > ANY VALUE

海山PG的设计使默认排序规则与BTree索引顺序一致,在海山PG中,BTree索引同样将NULL视为大于任何非NULL值,因此:

(1)ORDER BY col ASC 可以直接利用ASC索引顺序扫描

(2)ORDER BY col DESC 可以直接利用反向索引扫描

这种一致性使得很多ORDER BY查询能够直接通过Index Scan返回有序结果,从而避免额外的Sort操作,提高查询效率。

因此,在实现MySQL兼容数据库时,需要同时考虑两个方面:

(1)排序结果兼容性

MySQL默认行为为

ASC → NULL FIRST

DESC → NULL LAST

(2)索引使用与执行计划稳定性

如果简单修改海山PG内核,使其NULL比较逻辑变为NULL < ANY VALUE,虽然可以获得与MySQL一致的排序结果,但会导致BTree 索引顺序与排序规则不一致,从而使很多原本可以利用索引的ORDER BY查询退化为:

Index Scan

Sort

Seq Scan

Sort

这将带来明显的性能下降。

最后修改时间:2026-06-22 16:03:52
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论