当前位置: 首页 > news >正文

Oracle、MySQL、PostGreSQL、SQL Server-空值

Oracle、MySQL、PostGreSQL、SQL Server-null value

最近几年数据库市场百花齐放,在做跨数据库迁移的数据库选型时,除了性能、稳定、安全、运维、功能、可扩展外,像开发中对于值的处理往往容易被人忽视, 之前写过一篇关于PG区别Oracle在SQL解析缓存的笔记《PostgreSQL 12 : Prepare statement和plan_cache_mode 参数》,这里记录一下null 值在这几个数据库中的区别。

软件版本:Oracle 21c 、SQL Server 2019 、MySQL 8.0 、Mariadb 10.6 、PostGreSQL 13、OpenGauss 2.0

创建测试用例表

CREATE TABLE tab_null(id int, name char(10));INSERT INTO tab_null VALUES(1,'anbob');
INSERT INTO tab_null VALUES(2,NULL);

测试数据过滤

# oracle
SQL> select * from tab_null where name is null;ID NAME
---------- ----------2SQL> select * from tab_null where name is not null;ID NAME
---------- ----------1 anbobSQL> select * from tab_null where name=null;
no rows selectedSQL> select * from tab_null where null=null;
no rows selected# postgresql
postgres=# select * from tab_null where name is null;id | name
----+------2 |
(1 row)postgres=# select * from tab_null where name is not null;id |    name
----+------------1 | anbob
(1 row)postgres=# select * from tab_null where name=null;id | name
----+------
(0 rows)postgres=# select * from tab_null where null=null;id | name
----+------
(0 rows)# MySQL/MariaDB
mysql> select * from tab_null where name is null;
+------+------+
| id   | name |
+------+------+
|    2 | NULL |
+------+------+
1 row in set (0.00 sec)mysql> select * from tab_null where name is not null;
+------+-------+
| id   | name  |
+------+-------+
|    1 | anbob |
+------+-------+
1 row in set (0.00 sec)mysql> select * from tab_null where name=null;
Empty set (0.00 sec)mysql> select * from tab_null where null=null;
Empty set (0.00 sec)# SQL Serverselect * from tab_null where name is null;ID NAME
---------- ----------2select * from tab_null where name is not null;ID NAME
---------- ----------1 anbobselect * from tab_null where name=null;
no rows selectedselect * from tab_null where null=null;
no rows selected

Note:
可见所有数据库的结果是一样的。

# Mysql
mysql> select 1 from tab_null where 1 not in (null);
Empty set (0.00 sec)mysql> select 1 from tab_null where null not in (null);
Empty set (0.00 sec)mysql> select 1 from tab_null where null  in (null);
Empty set (0.00 sec)mysql> select 1 from tab_null where exists(select null from dual);
+---+
| 1 |
+---+
| 1 |
| 1 |
| 1 |
+---+
3 rows in set (0.05 sec)

Note:
这类在4个库返回也是一样的,上面只附了MySQL,不再展示其它库。

唯一约束

# oracle
SQL> alter table tab_null add constraint c_tab_null_name_uni  unique(name);
Table altered.SQL> INSERT INTO tab_null VALUES(3,NULL);
1 row created.SQL> select * from tab_null;ID NAME
---------- ----------1 anbob23
# postgresql
postgres=# alter table tab_null add constraint c_tab_null_name_uni  unique(name);
ALTER TABLE
postgres=# INSERT INTO tab_null VALUES(3,NULL);
INSERT 0 1
postgres=# select * from tab_null;id |    name
----+------------1 | anbob2 |3 |
(3 rows)# MySQL/MariaDB
mysql> alter table tab_null add constraint c_tab_null_name_uni  unique(name);
Query OK, 0 rows affected (0.14 sec)
Records: 0  Duplicates: 0  Warnings: 0mysql> INSERT INTO tab_null VALUES(3,NULL);
Query OK, 1 row affected (0.01 sec)mysql> select * from tab_null;
+------+-------+
| id   | name  |
+------+-------+
|    1 | anbob |
|    2 | NULL  |
|    3 | NULL  |
+------+-------+
3 rows in set (0.00 sec)# SQL SERVER
alter table tab_null add constraint c_tab_null_name_uni  unique(name);INSERT INTO tab_null VALUES(3,NULL);
Msg 2627 Level 14 State 1 Line 12
Violation of UNIQUE KEY constraint 'c_tab_null_name_uni'. 
Cannot insert duplicate key in object 'dbo.tab_null'. The duplicate key value is (<NULL>).

Note:
这里只有SQL SERVER提示一个表中的null和null是重复记录, 其它库可以正常insert 多个 null 到有唯一约束的表。

NULL使用索引

# MySQL/MariaDB
mysql> alter table tab_null drop constraint c_tab_null_name_uni;
Query OK, 0 rows affected (0.05 sec)
Records: 0  Duplicates: 0  Warnings: 0mysql> create index idx_tab_null_name on tab_null(name);
Query OK, 0 rows affected (0.05 sec)
Records: 0  Duplicates: 0  Warnings: 0mysql> explain select * from tab_null where name is null;
+----+-------------+----------+------------+------+-------------------+-------------------+---------+-------+------+----------+-----------------------+
| id | select_type | table    | partitions | type | possible_keys     | key               | key_len | ref   | rows | filtered | Extra                 |
+----+-------------+----------+------------+------+-------------------+-------------------+---------+-------+------+----------+-----------------------+
|  1 | SIMPLE      | tab_null | NULL       | ref  | idx_tab_null_name | idx_tab_null_name | 41      | const |    2 |   100.00 | Using index condition |
+----+-------------+----------+------------+------+-------------------+-------------------+---------+-------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)# PostgreSQL
postgres=# alter table tab_null drop constraint c_tab_null_name_uni;
ALTER TABLE
postgres=# create index idx_tab_null_name on tab_null(name);
CREATE INDEX
postgres=# explain analyze select * from tab_null where name is null;QUERY PLAN
---------------------------------------------------------------------------------------------------Seq Scan on tab_null  (cost=0.00..1.03 rows=1 width=18) (actual time=0.008..0.009 rows=2 loops=1)Filter: (name IS NULL)Rows Removed by Filter: 1Planning Time: 0.130 msExecution Time: 0.019 ms
-- 因为小表代价,这是使用了seq scan 全表扫,下面往表里insert一些数据postgres=# insert into tab_null select generate_series,generate_series||'anbob' from generate_series(101,10000);
INSERT 0 9900
postgres=# analyze tab_null;
ANALYZE
postgres=# explain analyze select * from tab_null where name is null;QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------Index Scan using idx_tab_null_name on tab_null  (cost=0.29..9.64 rows=2 width=15) (actual time=0.010..0.011 rows=2 loops=1)Index Cond: (name IS NULL)Planning Time: 0.199 msExecution Time: 0.031 ms
(4 rows)# Oracle
SQL>alter table tab_null drop constraint c_tab_null_name_uni;
Table altered.SQL> create index idx_tab_null_name on tab_null(name);
Index created.SQL> explain plan for select /*+index(t)*/ * from tab_null t where name is null;Explained.SQL> @x2PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------
Plan hash value: 2647411751------------------------------------------------------------------------------
| Id  | Operation         | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |          |     2 |    50 |     2   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| TAB_NULL |     2 |    50 |     2   (0)| 00:00:01 |
------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------1 - filter("NAME" IS NULL)Hint Report (identified by operation id / Query Block Name / Object Alias):
Total hints for statement: 1 (U - Unused (1))
---------------------------------------------------------------------------1 -  SEL$1 / "T"@"SEL$1"U -  index(t)-- 解决这个问题可以增加常数的复合索引SQL> create index idx_tab_null_name_0 on tab_null(name,0);
Index created.SQL> explain plan for select /*+index(t)*/ * from tab_null t where name is null;
Explained.SQL> @x2
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------
Plan hash value: 2247804559-----------------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name                | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |                     |     2 |    50 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| TAB_NULL            |     2 |    50 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN                  | IDX_TAB_NULL_NAME_0 |     1 |       |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------2 - access("NAME" IS NULL)# SQL SERVER
SET statistics profile on;
SELECT * FROM tab_null with (index(idx_tab_null_name)) Where name IS NULL;

image-20230916201149290

Note:
对于is null的谓词条件注意MySQL、MariaDB即使很少的记录也使用的index感觉更像是RULE CBO;

PostgreSQL开始使用了全表扫,也可能是基于代价的估算,全表扫要优于使用索引,因为pg默认没有像oracle,sql server, mysql 自带的hint可以强制使用索引,后来我们填充了更多的数据,PostgreSQL也使用上了索引,当然PG 也有扩展pg_hint_plan可以实现,不过PG认为用户中使用hint干扰优化器是不好的习惯,不应该那么做;

Oracle数据库因为单列索引不会储存null值,所以is null 即使使用hint 也无法使用索引,需要优化小技巧,增加常量的复合索引使用索引;

SQL Server同样我们在加hint with (index(idx_tab_null_name))后,执行计划中的Index Seek 也可以确认用上了索引。

字符串拼接

# sql server 2019
select null+'anbob'-------------
null# mariadb 10.6
select null+'anbob'-------------
null# mysql 8.0
select null+'anbob'-------------
null# postgres 13
postgres=# select 'anbob'||null;?column?
----------(1 row)# oracle 21c
SQL> select null||'anbob' from dual;NULL|
-----
anbob# OpenGauss
[og@oel7db1 data]$ gsql -d anbob -p 15432
gsql ((openGauss 2.0.0 build 78689da9) compiled at 2021-03-31 21:04:03 commit 0 last mr  )
NOTICE : The password has been expired, please change the password.
Non-SSL connection (SSL connection is recommended when requiring high-security)
Type "help" for help.^
anbob=# select null||'anbob' ;?column?
----------anbob
(1 row)

Note:
注意也是只有Oracle不同于其它库,在null值和其它字符串拼接后可以正常返回部分有效值,而其它所有库全部返回空。

总结:

对于null值的谓词过滤条件时(IS NULL、IS NOT NULL, >,< ,=),4个数据库返回数据记录是一样的;

对于null 值的唯一约束,只有SQL Server不允许null 记录重复,而其它数据库不限制;

对于is null使用Btree索引, 只有Oracle是默认无法索引的(需要创建常量的复合索引),其它数据库优化器在认为合适时可以正常使用索引;

对于null与字符串拼接就更有意思,sql server\postgresql\mysql在与null拼接后返回null, Oracle返回是字符串的值,而且基于Postgresql的OpenGauss返回和Oracle相同也是字符串,看来是与oracle做过兼容性修改。

相关文章:

Oracle、MySQL、PostGreSQL、SQL Server-空值

Oracle、MySQL、PostGreSQL、SQL Server-null value 最近几年数据库市场百花齐放&#xff0c;在做跨数据库迁移的数据库选型时&#xff0c;除了性能、稳定、安全、运维、功能、可扩展外&#xff0c;像开发中对于值的处理往往容易被人忽视&#xff0c; 之前写过一篇关于PG区别O…...

python pip详解1

一、简介 pip是python的一个软件包管理工具&#xff0c;同yum&#xff0c;apt作用一致&#xff0c;pip有两种使用方式&#xff1a;pip模块和pip命令&#xff0c;示例如下&#xff1a; python -m pip install package pip install package二、命令行详解 python -m pip --hel…...

Linux常用命令大全(超详细!!!)

文章目录 1.Linux是什么1.1 关于Linux我们主要学习什么1.1 学习Linux常见命令的前置知识 2. Linux常见命令2.1 ls命令2.2 cd命令2.3 pwd命令2.4 touch命令2.5 cat命令2.6 echo命令2.7 vim命令2.8 mkdir 命令2.9 rm命令2.10 cp命令2.11 mv命令2.12 grep命令2.13 ps命令2.14 nets…...

TDD测试驱动开发

为什么需要TDD&#xff1f; 传统开发方式&#xff0c;带来大量的低质量代码&#xff0c;而代码质量带来的问题&#xff1a; 1.在缺陷的泥潭中挣扎 开发长时间投入在缺陷的修复中&#xff0c;修复完依赖测试做长时间的回归测试 2.维护困难&#xff0c;开发缓慢 比如重复代码&am…...

huggingface镜像站

huggingface下载太慢&#xff0c;大模型文件太大。用huggingface_hub镜像。 pip install -U huggingface_hub pip install huggingface-cli export HF_ENDPOINThttps://hf-mirror.com huggingface-cli download --resume-download shenzhi-wang/Llama3-8B-Chinese-Chat --loc…...

Java中如何实现数据库连接池优化?

Java中如何实现数据库连接池优化&#xff1f; 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将深入探讨在Java应用程序中如何实现数据库连接池优化&am…...

002 SpringMVC入门项目搭建

文章目录 HelloController.javaspringmvc.xmlweb.xmlpom.xmlhello.jsp http://localhost:8080/showView http://localhost:8080/showData HelloController.java package com.springmvc.controller;import org.springframework.stereotype.Controller; import org.springframewo…...

为什么要使用多线程(并发编程)

目录 1.上下文的切换 1.1 什么是上下文切换 2. 并发编程的死锁问题 2.1 死锁产生的原因 2.2 避免死锁的方法 3.资源限制的挑战3.1 什么是资源限制 并发编程的目的是为了让程序更快&#xff0c;大家都知道并不是开启的线程越多越快&#xff0c;因为开启的线程越多随即面临…...

Unity编辑器工具---版本控制与自动化打包工具

Unity - 特殊文件夹【作用与是否会被打包到build中】 Unity编辑器工具—版本控制与自动化打包工具&#xff1a; 面板显示&#xff1a;工具包含一个面板&#xff0c;用于展示软件的不同版本信息。版本信息&#xff1a;面板上显示主版本号、当前版本号和子版本号。版本控制功能…...

amis-editor 注册自定义组件

建议先将amis文档从头到尾&#xff0c;仔细看一遍。 参考&#xff1a;amis - 低代码前端框架 amis 的渲染过程是将 json 转成对应的 React 组件。先通过 json 的 type 找到对应的 Component&#xff0c;然后把其他属性作为 props 传递过去完成渲染。 import * as React from …...

(上位机APP开发)调用华为云命令API接口给设备下发命令

一、功能说明 通过调用华为云IOT提供的命令下发API接口,实现下面界面上相同的功能。调用API接口给设备下发命令。 二、JavaScript代码 function sendUnlockCommand() {var requestUrl = "https://9bcf4cfd30.st1.iotda-app.cn-north-4.myhuaweicloud.com:443/v5/iot/60…...

排序算法系列一:选择排序、插入排序 与 希尔排序

目录 零、说在前面 一、理论部分 1.1&#xff1a;选择排序 1.1.1&#xff1a;算法解读&#xff1a; 1.1.2&#xff1a;时间复杂度 1.1.3&#xff1a;优缺点&#xff1a; 1.1.4&#xff1a;代码&#xff1a; 1.2&#xff1a;插入排序 1.2.1&#xff1a;算法解读&#x…...

【快速排序】| 详解快速排序 力扣912

&#x1f397;️ 主页&#xff1a;小夜时雨 &#x1f397;️专栏&#xff1a;快速排序 &#x1f397;️如何活着&#xff0c;是我找寻的方向 目录 1. 题目解析2. 代码 1. 题目解析 题目链接: https://leetcode.cn/problems/sort-an-array/ 我们上道题讲过快速排序的核心代码&a…...

游戏推荐: 植物大战僵尸杂交版

下载地址网上一搜就有. 安装就能玩. 2是显血. 4显示植物血, 5是加速. 都是左手主键盘的按钮, 再按是取消. 比较刺激: ps: 设置里面还能打开自动收集阳光和金币....

微调和rag的区别?

微调和RAG&#xff08;Retrieval-Augmented Generation&#xff09;在多个维度上存在显著的区别。以下是它们之间的主要差异&#xff1a; 1. **知识维度**&#xff1a; - RAG对知识的更新时间和经济成本更低。它不需要训练&#xff0c;只需要更新数据库即可。 - RAG对知识的掌控…...

CVPR讲座总结(二)-探索图像生成基础模型的最新进展探索多模态代理的最新进展:从视频理解到可操作代理

引言 在CVPR24上的教程中&#xff0c;微软高级研究员Linjie Li为我们带来了多模态代理的深入探索。这些代理通过整合多模态专家和大语言模型&#xff08;LLM&#xff09;来增强感知、理解和生成能力。本文总结了Linjie Li的讲座内容&#xff0c;重点介绍了多模态记忆、可操作代…...

为什么要禁用透明大页面

在安装CDH&#xff08;Clouderas Distribution Including Apache Hadoop&#xff09;环境时&#xff0c;禁用透明大页面&#xff08;Transparent HugePages&#xff0c;THP&#xff09;是一个推荐的系统优化步骤。以下是禁用透明大页面的一些原因&#xff1a; 1. **性能影响**…...

Element 页面滚动表头置顶

在开发后台管理系统时&#xff0c;表格是最常用的一个组件&#xff0c;为了看数据方便&#xff0c;时常需要固定表头。 如果页面基本只有一个表格区域&#xff0c;我们可以根据屏幕的高度动态的计算出一个值&#xff0c;给表格设定一个固定高度&#xff0c;这样表头就可以固定…...

对于CDA一级考试该咋准备??!

一、了解考试内容和结构 CDA一级考试主要涉及的内容包括&#xff1a;数据分析概述与职业操守、数据结构、数据库基础与数据模型、数据可视化分析与报表制作、Power BI应用、业务数据分析与报告编写等。 CDA Level Ⅰ 认证考试大纲:https://edu.cda.cn/group/4/thread/174335 …...

如何使用PHP和Selenium快速构建自己的网络爬虫系统

近年来&#xff0c;随着互联网的普及&#xff0c;网络爬虫逐渐成为了信息采集的主要手段之一&#xff0c;然而&#xff0c;常规的爬虫技术不稳定、难以维护&#xff0c;市面上的纯web网页爬虫也只能在静态页面上进行操作。而php结合selenium可达到动态爬虫的效果&#xff0c;具…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

Spring Boot 实现流式响应(兼容 2.7.x)

在实际开发中&#xff0c;我们可能会遇到一些流式数据处理的场景&#xff0c;比如接收来自上游接口的 Server-Sent Events&#xff08;SSE&#xff09; 或 流式 JSON 内容&#xff0c;并将其原样中转给前端页面或客户端。这种情况下&#xff0c;传统的 RestTemplate 缓存机制会…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

【项目实战】通过多模态+LangGraph实现PPT生成助手

PPT自动生成系统 基于LangGraph的PPT自动生成系统&#xff0c;可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析&#xff1a;自动解析Markdown文档结构PPT模板分析&#xff1a;分析PPT模板的布局和风格智能布局决策&#xff1a;匹配内容与合适的PPT布局自动…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

C++八股 —— 单例模式

文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全&#xff08;Thread Safety&#xff09; 线程安全是指在多线程环境下&#xff0c;某个函数、类或代码片段能够被多个线程同时调用时&#xff0c;仍能保证数据的一致性和逻辑的正确性&#xf…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别

【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而&#xff0c;传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案&#xff0c;能够实现大范围覆盖并远程采集数据。尽管具备这些优势&#xf…...

站群服务器的应用场景都有哪些?

站群服务器主要是为了多个网站的托管和管理所设计的&#xff0c;可以通过集中管理和高效资源的分配&#xff0c;来支持多个独立的网站同时运行&#xff0c;让每一个网站都可以分配到独立的IP地址&#xff0c;避免出现IP关联的风险&#xff0c;用户还可以通过控制面板进行管理功…...