本文阅读时间大约6分钟。

其实写这篇文章,也是来自一个知识星球读者的提问,他在二面的过程中被问到了,由于他简历中写道有 MySQL 调优经验,但这个问题没有回答好,二面被刷了。

其实我们刚学习 C 语言的时候,就接触过 NULL,比如下面这句代码。

int *p = NULL;

它实际上表示将指针指向一块不被使用的内存地址,一般会在宏中定义好。

那么我们常用的 Java 语言,同样也用到 null,表示一个空引用,如果你不小心引用了,那么就会抛出 NullPointerException,就像昨天 Reddit 上面很火的一张图。

关于空指针异常,我之前写过一篇文章来介绍怎么防御《java.lang.NullPointerException》。但是这篇文章没有写全,今天在这里补充一下。

其实很早之前 guava 就提供了 Optional 容器类来处理 null,其目的便是避免猝不及防的空指针。后来 java8 直接引入了 Optional,功能一样,用法上稍稍有点变化。其实还有很多开源框架,比如 Spring,common lang3等,也提供了处理空的工具类,如。

StringUtils.isBlank();

CollectionUtils.isEmpty();

那么在 MySQL 中,NULL 表示不知道的数据。

我们在设计表的时候,经常会有老司机这么告诉我们。

字段尽可能用NOT NULL,而不是NULL,除非特殊情况。

这句话到底有没有错?

可以负责任的告诉你这句话没有错,也不是以讹传讹。

这句话首次出现在 MySQL 官网。

如果你读过《高性能 MySQL》这本书,你应该会看到这么一段,在 4.1 节提到。

由此看来,把 NULL 改成 NOT NULL 对索引的性能并没有明显的提升。避免使用 NULL 的目的,是便于代码的可读性和可维护性。同时也便于避免下文即将出现的一些稀奇古怪的错误。

好了,下面咱们通过实验来看看,使用 NULL 会出现那些稀奇古怪的错误呢?

跟我一样在本地建两个表 t1,t2;其中一个表 name 字段允许为空,另一个表 name 字段不允许为空,分别对 name 字段建立索引,SQL 语句如下。

1、NOT IN、!= 等负向条件查询在有 NULL 值的情况下返回非空行的结果集。

比如上例中的 t2,我执行如下 SQL 语句。

SELECT * from t2 where name != '张三'

你本打算返回 id 为 2 的那行数据,然而什么都没有。

又比如这条 SQL 语句。

select * from t2 where name not in (select name from t2 where id!=1)

也返回了空结果集。

2、使用 concat 函数拼接时,首先要对各个字段进行非 NULL 判断,否则只要任何一个字段为空都会造成拼接的结果为 NULL。

比如下面这条 SQL 语句。

SELECT CONCAT("1",NULL)

3、当用count函数进行统计时,NULL 列不会计入统计。

SELECT count(name) from t2

4、查询空行数据,用 is NULL。

SELECT * FROM t2 where name is NULL

5、NULL 列需要更多的存储空间,一般需要一个额外的字节作为判断是否为 NULL 的标志位。

如果你仔细观察 t1 和 t2 表的 key_len,会发现 t2 比 t1 多了一个字节。

explain SELECT * from t2 where name = '张三'

explain SELECT * from t1 where name = '张三'

key_len 的长度一般跟这三个因素有关,分别是数据类型字符编码是否为 NULL

因此,t2 比 t1 多出的这一个字节,用于作为判断是否为 NULL 的标志位了。

马蛋,原来一切都在书中。如果面试的哪位同学多读几篇《高性能 MySQL》这本书,那个岗位就是他的了,但没有那么多如果。。。

在此,建议大家多看官方文档,多读点好书,多关注一些良心的原创技术自媒体,不要看那些无凭无据的文章,反而会以讹传讹,贻害无穷。

如果这篇文章对你有帮助,麻烦分享到你的朋友圈,来帮助更多的朋友。

参考

https://dev.mysql.com/doc/refman/5.7/en/dynamic-format.html

https://dev.mysql.com/doc/refman/5.5/en/problems-with-null.html

https://dev.mysql.com/doc/refman/5.5/en/multiple-column-indexes.html

https://dev.mysql.com/doc/internals/en/myisam-introduction.html

https://dev.mysql.com/doc/internals/en/innodb-field-contents.html

下方查看历史文章

面试官:讲讲redis的过期策略如何实现?

【译】深入理解G1的GC日志(一)

使用Optional摆脱NPE的折磨

025:为什么需要将Logger对象声明为private static final类型的

本号专注于后端技术、JVM问题排查和优化、Java面试题、个人成长和自我管理等主题,为读者提供一线开发者的工作和成长经验,期待你能在这里有所收获。

让我知道你“在看”

面试官问我,为什么老司机建议MySQL列属性尽量用 NOT NULL ?的更多相关文章

  1. 面试官问,说一个你在工作非常有价值的bug

    如果你去参考面试,做足了准备,面对面试官员从容不迫,吐沫横飞的大谈自己的工作经历.突然,面试官横插一句:说一个你在工作非常有价值的bug.顿时,整个空气都仿佛都凝固了!“What?”... 我想没几个 ...

  2. 面试官问我,Redis分布式锁如何续期?懵了。

    前言 上一篇[面试官问我,使用Dubbo有没有遇到一些坑?我笑了.]之后,又有一位粉丝和我说在面试过程中被虐了.鉴于这位粉丝是之前肥朝的粉丝,而且周一又要开启新一轮的面试,为了回馈他长期以来的支持,所 ...

  3. 当面试官问我ArrayList和LinkedList哪个更占空间时,我这么答让他眼前一亮

    前言 今天介绍一下Java的两个集合类,ArrayList和LinkedList,这两个集合的知识点几乎可以说面试必问的. 对于这两个集合类,相信大家都不陌生,ArrayList可以说是日常开发中用的 ...

  4. 面试官问:HashMap在并发情况下为什么造成死循环?一脸懵

    这个问题是在面试时常问的几个问题,一般在问这个问题之前会问Hashmap和HashTable的区别?面试者一般会回答:hashtable是线程安全的,hashmap是线程不安全的. 那么面试官就会紧接 ...

  5. 「每日一题」有人上次在dy面试,面试官问我:vue数据绑定的实现原理。你说我该如何回答?

    关注「松宝写代码」,精选好文,每日一题 ​时间永远是自己的 每分每秒也都是为自己的将来铺垫和增值 作者:saucxs | songEagle 来源:原创 一.前言 文章首发在「松宝写代码」 2020. ...

  6. [每日一题]面试官问:Async/Await 如何通过同步的方式实现异步?

    关注「松宝写代码」,精选好文,每日一题 ​时间永远是自己的 每分每秒也都是为自己的将来铺垫和增值 作者:saucxs | songEagle 一.前言 2020.12.23 日刚立的 flag,每日一 ...

  7. [每日一题]面试官问:for in和for of 的区别和原理?

    关注「松宝写代码」,精选好文,每日一题 ​时间永远是自己的 每分每秒也都是为自己的将来铺垫和增值 作者:saucxs | songEagle 一.前言 2020.12.23 日刚立的 flag,每日一 ...

  8. 每日一问:面试结束时面试官问"你有什么问题需要问我呢",该如何回答?

    面试结束时面试官问"你有什么问题需要问我呢",该如何回答?

  9. 面试官问:JS的this指向

    前言 面试官出很多考题,基本都会变着方式来考察this指向,看候选人对JS基础知识是否扎实.读者可以先拉到底部看总结,再谷歌(或各技术平台)搜索几篇类似文章,看笔者写的文章和别人有什么不同(欢迎在评论 ...

随机推荐

  1. COOKIE&SESSION 入门

    JSP.EL 表达式的入门(重点) Servlet/JSP 是两种动态的 WEB 资源的两种技术. ** Servlet 的缺点 ** 开发人员要十分熟悉 JAVA 不便于页面调试和维护 修改.重新编 ...

  2. Django2.2 Vue 前后端分离 无法访问Cookie

    个人验证后可用配置如下: 环境: - Django 2.2 - djangorestframework 3.9 - django-cors-headers 2.5.3 INSTALLED_APPS = ...

  3. Linux路由器及交换机工作原理

    IP包头中TTL字段的含义是什么?它用来做什么? TTL(time to live):该字段用于表示IP数据包的生命周期, 作用:限制一个数据在网络中无限循环的转发下去. 简述arp缓存表的建立过程: ...

  4. Python数据分析与爬虫

    数据分析重要步骤: 1.数据获取  可以进行人工收集获取部分重要数据 可以在各个数据库中导出数据 使用Python的爬虫等技术 2.数据整理  从数据库.文件中提取数据,生成DataFrame对象 采 ...

  5. Linux性能优化实战学习笔记:第五十讲

    一.上节回顾 上一节,我以 ksoftirqd CPU 使用率高的问题为例,带你一起学习了内核线程 CPU 使用率高时的分析方法.先简单回顾一下. 当碰到内核线程的资源使用异常时,很多常用的进程级性能 ...

  6. dskms改为ckplayer播放器

    将ckplayer代码文件夹上传到/var/www/html/public/static/plugins/目录下修改/var/www/html/application/home/view/defaul ...

  7. 编程哲理小故事:Tina的运动会方阵

    自从接到任务后,Tina一直 烦恼着如何让这群繁忙又缺乏才艺的程序员在运动会开幕式上做出一个有趣的方阵表演. 接到了运动会的方阵表演的任务 时间回到1个月前. Tina正在工位上繁忙地进行着下一期准备 ...

  8. pipeline 多个参数如何传入

    1.准备一个json文件 {    "NAME" : "Lucy",    ",    ",    "ADDRESS" ...

  9. 在Linux上利用curl 命令模拟 HTTP GET/POST 请求

    本文系转载,原文地址:https://www.cnblogs.com/alfred0311/p/7988648.html 序言 在 Linux 操作系统上对后端程序进行测试的时候,需要进行模拟连接或者 ...

  10. ElasticSearch : High Rest Api 使用

    pom文件: <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId> ...