【MySQL】 IS NOT NULL 和 != NULL 的区别?

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

背景

最近在开发小伙伴的需求遇到了一个数据库统计的问题
is not null 结果正确
=null 结果就不对然后就激发了获取真理的想法那必须的查查
咋回事嘞
在这里插入图片描述

开整

在用MySQL的过程中你是否存在过如下的几个疑问

  • 我的字段类型明明指定的是NOT NULL但是为什么还是可以插入空值呢
  • 为什么NOT NULL的效率比NULL更高
  • 在查询空字段的记录时是用"select * from table where col <> ‘’ “还是用"select * from table where col is not null”

带着疑问我们来看看NOT NULL和NULL有什么不一样呢要搞清楚这两个的区别。首先我们先要理解"空值"和"NULL"的含义

  • 空值是不占用空间的。
  • NULL是会占用空间的我们来看看官方对这个NULL的描述。MySQL的官方描述如下

“NULL columns require additional space in the row to record whether their values are NULL. For MyISAM tables, each NULL column takes one bit extra, rounded up to the nearest byte.”

怎么理解呢简单举个栗子

假设有一个瓶子空值表示的是瓶子里什么都没有NULL表示的是瓶子里面状态的是空气。可以理解为什么NULL也会占用空间了吧。

下面来通过一个实例例子来测试一下。首先建一个表表引擎使用InnoDB建表语句如下

create table test(
  c1 varchar(10) not null, 
  c2 varchar(10) default null
) engine = InnoDB;

验证插入数据和查询

mysql> insert into test(c1, c2) values(null, 0);
ERROR 1048 (23000): Column 'c1' cannot be null

mysql> insert into test(c1, c2) values('', 0);
Query OK, 1 row affected (0.00 sec)
# null字符串
mysql> insert into test(c1, c2) values('null', 0);
Query OK, 1 row affected (0.00 sec)

mysql> insert into test(c1, c2) values('', null);
Query OK, 1 row affected (0.00 sec)

mysql> select * from test;
+------+------+
| c1   | c2   |
+------+------+
|      | 0    |
| null | 0    |
|      | NULL |
+------+------+
3 rows in set (0.00 sec)

从上述结果中可以看到NOT NULL的字段是没办法插入NULL值的只能插入空值’'。上面第三个SQL插入的NULL是个字符串格式的NULL对于MyISAM的存储引擎测试的结果和上述结果是一样的。所以第1个疑问也就了解了吧。

对于第2个问题因为NULL值是占了一定空间的所以在MySQL进行字段比较的时候值为NULL的字段也是会参与比较的所以是会对性能有一定的影响。

当字段上包含有索引时由于B树索引是不会存储NULL值的所以在使用这个字段做为查询条件时对性能的影响还是比较大的在平时创建索引的时候应该尽量保证列的值不为NULL。

针对上述的结论有几个针对NULL和NOT NULL的常见优化建议

  • MySQL如果不指定列的约束默认就是允许NULLTIMESTAMP类型的字段除外。所以在非必要情况下尽量设置列的约束为NOT NULL。
  • 如果列的值为NULL通过这个为NULL的列进行条件查询时MySQL更难做优化因为为NULL的列会让索引的统计和值的比较更加复杂。
  • 如果计划在某个列上创建索引那么需要尽量避免这个列中的字段值为NULL。在优化的过程中把NULL改为NOT NULL对性能的提升并不是很明显。所以如果在使用过程中没有问题的话没有必要首先去做NULL到NOT NULL的优化。

来通过实际例子看看最后一个问题。假如需要查询上述test表中c1不为空的所有数据应该使用"<> ‘’"呢还是使用"IS NOT NULL"呢测试结果如下

mysql> select * from test where c1 is not null;
+------+------+
| c1   | c2   |
+------+------+
|      | 1    |
| null | 1    |
|      | NULL |
+------+------+
3 rows in set (0.00 sec)

mysql> select * from test where c1 <> '';
+------+------+
| c1   | c2   |
+------+------+
| null | 1    |
+------+------+
1 row in set (0.00 sec)

可以看到不同的查询条件对于查询的结果区别还是特别大的。所以在使用过程中需要根据业务场景选择不同的查询条件。

附录

附录1MySQL索引失效的常见情况

  1. 最左前缀原则。例如存在联合索引idx_a_b(a, b)查询条件使用where b = 1则无法使用索引
  2. LIKE 前置模糊查询。例如col_name like '%test'col_name like '%test%'
  3. 索引列使用函数或存在计算。例如存在索引idx_col(col)查询条件使用where left(col, 2) = 'te'
  4. 查询条件使用 is not null。设计表结构时尽量设置 not null约束
  5. 字段类型出现隐式转换。例如存在字段test_colvarchar类型查询时使用了where test_col = 1隐式转为了int类型导致索引失效
  6. 条件中有 or 存在可能不会使用索引。例如查询条件为where a = 'testa' or b = 'testb'存在索引idx_a(a)此时也不会使用索引除非为b字段也添加索引
  7. 查询结果超过整体结果的25%或三分之一或者表数据量比较少时MySQL认为全表扫描代价更小会导致索引失效

附录2MySQL关键字列表

R 表示为 MySQL 预留关键字

关键字关键字关键字
ACCESSIBLERACCOUNTACTION
ADDRAFTERAGAINST
AGGREGATEALGORITHMALLR
ALTERRALWAYSANALYSE
ANALYZERANDRANY
ASRASCRASCII
ASENSITIVERATAUTOEXTEND_SIZE
AUTO_INCREMENTAVGAVG_ROW_LENGTH
BACKUPBEFORERBEGIN
BETWEENRBIGINTRBINARYR
BINLOGBITBLOBR
BLOCKBOOLBOOLEAN
BOTHRBTREEBYR
BYTECACHECALL ®
CASCADE ®CASCADEDCASE ®
CATALOG_NAMECHAINCHANGE ®
CHANGEDCHANNELCHAR ®
CHARACTER ®CHARSETCHECK ®
CHECKSUMCIPHERCLASS_ORIGIN
CLIENTCLOSECOALESCE
CODECOLLATE ®COLLATION
COLUMN ®COLUMNSCOLUMN_FORMAT
COLUMN_NAMECOMMENTCOMMIT
COMMITTEDCOMPACTCOMPLETION
COMPRESSEDCOMPRESSIONCONCURRENT
CONDITION ®CONNECTIONCONSISTENT
CONSTRAINT ®CONSTRAINT_CATALOGCONSTRAINT_NAME
CONSTRAINT_SCHEMACONTAINSCONTEXT
CONTINUE ®CONVERT ®CPU
CREATE ®CROSS ®CUBE
CURRENTCURRENT_DATE ®CURRENT_TIME ®
CURRENT_TIMESTAMP ®CURRENT_USER ®CURSOR ®
CURSOR_NAMEDATADATABASE ®
DATABASES ®DATAFILEDATE
DATETIMEDAYDAY_HOUR ®
DAY_MICROSECOND ®DAY_MINUTE ®DAY_SECOND ®
DEALLOCATEDEC ®DECIMAL ®
DECLARE ®DEFAULT ®DEFAULT_AUTH
DEFINERDELAYED ®DELAY_KEY_WRITE
DELETE ®DESC ®DESCRIBE ®
DES_KEY_FILEDETERMINISTIC ®DIAGNOSTICS
DIRECTORYDISABLEDISCARD
DISKDISTINCT ®DISTINCTROW ®
DIV ®DODOUBLE ®
DROP ®DUAL ®DUMPFILE
DUPLICATEDYNAMICEACH ®
ELSE ®ELSEIF ®ENABLE
ENCLOSED ®ENCRYPTIONEND
ENDSENGINEENGINES
ENUMERRORERRORS
ESCAPEESCAPED ®EVENT
EVENTSEVERYEXCHANGE
EXECUTEEXISTS ®EXIT ®
EXPANSIONEXPIREEXPLAIN ®
EXPORTEXTENDEDEXTENT_SIZE
FALSE ®FASTFAULTS
FETCH ®FIELDSFILE
FILE_BLOCK_SIZEFILTERFIRST
FIXEDFLOATRFLOAT4R
FLOAT8RFLUSHFOLLOWS
FORRFORCERFOREIGNR
FORMATFOUNDFROMR
FULLFULLTEXTRFUNCTION
GENERALGENERATEDRGEOMETRY
GEOMETRYCOLLECTIONGETRGET_FORMAT
GLOBALGRANTRGRANTS
GROUPRGROUP_REPLICATIONHANDLER
HASHHAVINGRHELP
HIGH_PRIORITYRHOSTHOSTS
HOURHOUR_MICROSECONDRHOUR_MINUTER
HOUR_SECONDRIDENTIFIEDIFR
IGNORERIGNORE_SERVER_IDSIMPORT
INRINDEXRINDEXES
INFILERINITIAL_SIZEINNERR
INOUTRINSENSITIVERINSERTR
INSERT_METHODINSTALLINSTANCE
INTRINT1RINT2R
INT3RINT4RINT8R
INTEGERRINTERVALRINTOR
INVOKERIOIO_AFTER_GTIDSR
IO_BEFORE_GTIDSRIO_THREADIPC
ISRISOLATIONISSUER
ITERATERJOINRJSON
KEYRKEYSRKEY_BLOCK_SIZE
KILLRLANGUAGELAST
LEADINGRLEAVE ®LEAVES
LEFT ®LESSLEVEL
LIKE ®LIMIT ®LINEARR
LINESRLINESTRINGLIST
LOADRLOCALLOCALTIMER
LOCALTIMESTAMPRLOCKRLOCKS
LOGFILELOGSLONGR
LONGBLOBRLONGTEXTRLOOPR
LOW_PRIORITYRMASTERMASTER_AUTO_POSITION
MASTER_BINDRMASTER_CONNECT_RETRYMASTER_DELAY
MASTER_HEARTBEAT_PERIODMASTER_HOSTMASTER_LOG_FILE
MASTER_LOG_POSMASTER_PASSWORDMASTER_PORT
MASTER_RETRY_COUNTMASTER_SERVER_IDMASTER_SSL
MASTER_SSL_CAMASTER_SSL_CAPATHMASTER_SSL_CERT
MASTER_SSL_CIPHERMASTER_SSL_CRLMASTER_SSL_CRLPATH
MASTER_SSL_KEYMASTER_SSL_VERIFY_SERVER_CERTRMASTER_TLS_VERSION
MASTER_USERMATCHRMAXVALUER
MAX_CONNECTIONS_PER_HOURMAX_QUERIES_PER_HOURMAX_ROWS
MAX_SIZEMAX_STATEMENT_TIMEMAX_UPDATES_PER_HOUR
MAX_USER_CONNECTIONSMEDIUMMEDIUMBLOBR
MEDIUMINTRMEDIUMTEXTRMEMORY
MERGEMESSAGE_TEXTMICROSECOND
MIDDLEINTRMIGRATEMINUTE
MINUTE_MICROSECONDRMINUTE_SECONDRMIN_ROWS
MODRMODEMODIFIESR
MODIFYMONTHMULTILINESTRING
MULTIPOINTMULTIPOLYGONMUTEX
MYSQL_ERRNONAMENAMES
NATIONALNATURALRNCHAR
NDBNDBCLUSTERNEVER
NEWNEXTNO
NODEGROUPNONBLOCKINGNONE
NOTRNO_WAITNO_WRITE_TO_BINLOGR
NULLRNUMBERNUMERICR
NVARCHAROFFSETOLD_PASSWORD
ONRONEONLY
OPENOPTIMIZEROPTIMIZER_COSTSR
OPTIONROPTIONALLYROPTIONS
ORRORDERROUTR
OUTERROUTFILEROWNER
PACK_KEYSPAGEPARSER
PARSE_GCOL_EXPRPARTIALPARTITIONR
PARTITIONINGPARTITIONSPASSWORD
PHASEPLUGINPLUGINS
PLUGIN_DIRPOINTPOLYGON
PORTPRECEDESPRECISIONR
PREPAREPRESERVEPREV
PRIMARYRPRIVILEGESPROCEDURER
PROCESSLISTPROFILEPROFILES
PROXYPURGERQUARTER
QUERYQUICKRANGER
READRREADSRREAD_ONLY
READ_WRITERREALRREBUILD
RECOVERREDOFILEREDO_BUFFER_SIZE
REDUNDANTREFERENCESRREGEXPR
RELAYRELAYLOGRELAY_LOG_FILE
RELAY_LOG_POSRELAY_THREADRELEASER
RELOADREMOVERENAMER
REORGANIZEREPAIRREPEATR
REPEATABLEREPLACERREPLICATE_DO_DB
REPLICATE_DO_TABLEREPLICATE_IGNORE_DBREPLICATE_IGNORE_TABLE
REPLICATE_REWRITE_DBREPLICATE_WILD_DO_TABLEREPLICATE_WILD_IGNORE_TABLE
REPLICATIONREQUIRERRESET
RESIGNALRRESTORERESTRICTR
RESUMERETURNRRETURNED_SQLSTATE
RETURNSREVERSEREVOKER
RIGHTRRLIKERROLLBACK
ROLLUPROTATEROUTINE
ROWROWSROW_COUNT
ROW_FORMATRTREESAVEPOINT
SCHEDULESCHEMARSCHEMASR
SCHEMA_NAMESECONDSECOND_MICROSECONDR
SECURITYSELECTRSENSITIVER
SEPARATORRSERIALSERIALIZABLE
SERVERSESSIONSETR
SHARESHOWRSHUTDOWN
SIGNALRSIGNEDSIMPLE
SLAVESLOWSMALLINTR
SNAPSHOTSOCKETSOME
SONAMESOUNDSSOURCE
SPATIAL ®SPECIFIC ®SQL ®
SQLEXCEPTION ®SQLSTATE ®SQLWARNING ®
SQL_AFTER_GTIDSSQL_AFTER_MTS_GAPSSQL_BEFORE_GTIDS
SQL_BIG_RESULTRSQL_BUFFER_RESULTSQL_CACHE
SQL_CALC_FOUND_ROWSRSQL_NO_CACHESQL_SMALL_RESULTR
SQL_THREADSQL_TSI_DAYSQL_TSI_HOUR
SQL_TSI_MINUTESQL_TSI_MONTHSQL_TSI_QUARTER
SQL_TSI_SECONDSQL_TSI_WEEKSQL_TSI_YEAR
SSLRSTACKEDSTART
STARTINGRSTARTSSTATS_AUTO_RECALC
STATS_PERSISTENTSTATS_SAMPLE_PAGESSTATUS
STOPSTORAGESTOREDR
STRAIGHT_JOINRSTRINGSUBCLASS_ORIGIN
SUBJECTSUBPARTITIONSUBPARTITIONS
SUPERSUSPENDSWAPS
SWITCHESTABLERTABLES
TABLESPACETABLE_CHECKSUMTABLE_NAME
TEMPORARYTEMPTABLETERMINATEDR
TEXTTHANTHENR
TIMETIMESTAMPTIMESTAMPADD
TIMESTAMPDIFFTINYBLOBRTINYINTR
TINYTEXTRTORTRAILINGR
TRANSACTIONTRIGGER ®TRIGGERS
TRUE ®TRUNCATETYPE
TYPESUNCOMMITTEDUNDEFINED
UNDORUNDOFILEUNDO_BUFFER_SIZE
UNICODEUNINSTALLUNIONR
UNIQUERUNKNOWNUNLOCKR
UNSIGNEDRUNTILUPDATER
UPGRADEUSAGERUSER
USERUSER_RESOURCESUSE_FRM
USINGRUTC_DATERUTC_TIMER
UTC_TIMESTAMPRVALIDATIONVALUE
VALUESRVARBINARYRVARCHARR
VARCHARACTERRVARIABLESVARYINGR
VIEWVIRTUALRWAIT
WARNINGSWEEKWEIGHT_STRING
WHENRWHERERWHILER
WITHRWITHOUTWORK
WRAPPERWRITERX509
XAXIDXML
XORRYEARYEAR_MONTHR
ZEROFILLR
阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: mysql