背景
最近在開發(fā)小伙伴的需求,遇到了一個(gè)數(shù)據(jù)庫統(tǒng)計(jì)的問題,
is not null 結(jié)果正確
!=null 結(jié)果就不對(duì),然后就激發(fā)了獲取真理的想法,那必須的查查
咋回事嘞?
開整
在用MySQL的過程中,你是否存在過如下的幾個(gè)疑問?
- 我的字段類型明明指定的是NOT NULL,但是為什么還是可以插入空值呢?
- 為什么NOT NULL的效率比NULL更高?
- 在查詢空字段的記錄時(shí)是用"select * from table where col <> ‘’ “還是用"select * from table where col is not null”?
帶著疑問,我們來看看NOT NULL和NULL有什么不一樣呢?要搞清楚這兩個(gè)的區(qū)別。首先,我們先要理解"空值"和"NULL"的含義:
- 空值是不占用空間的。
- NULL是會(huì)占用空間的,我們來看看官方對(duì)這個(gè)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.”
怎么理解呢?簡單舉個(gè)栗子:
假設(shè)有一個(gè)瓶子,空值表示的是瓶子里什么都沒有,NULL表示的是瓶子里面狀態(tài)的是空氣??梢岳斫鉃槭裁碞ULL也會(huì)占用空間了吧。
下面來通過一個(gè)實(shí)例例子來測(cè)試一下。首先建一個(gè)表,表引擎使用InnoDB,建表語句如下:
create table test(
c1 varchar(10) not null,
c2 varchar(10) default null
) engine = InnoDB;
驗(yàn)證插入數(shù)據(jù)和查詢:
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)
從上述結(jié)果中可以看到,NOT NULL的字段是沒辦法插入NULL值的,只能插入空值’'。上面第三個(gè)SQL插入的NULL是個(gè)字符串格式的NULL,對(duì)于MyISAM的存儲(chǔ)引擎,測(cè)試的結(jié)果和上述結(jié)果是一樣的。所以第1個(gè)疑問也就了解了吧。
對(duì)于第2個(gè)問題,因?yàn)镹ULL值是占了一定空間的,所以在MySQL進(jìn)行字段比較的時(shí)候,值為NULL的字段也是會(huì)參與比較的,所以是會(huì)對(duì)性能有一定的影響。
當(dāng)字段上包含有索引時(shí),由于B樹索引是不會(huì)存儲(chǔ)NULL值的,所以在使用這個(gè)字段做為查詢條件時(shí),對(duì)性能的影響還是比較大的,在平時(shí)創(chuàng)建索引的時(shí)候,應(yīng)該盡量保證列的值不為NULL。
針對(duì)上述的結(jié)論,有幾個(gè)針對(duì)NULL和NOT NULL的常見優(yōu)化建議:
- MySQL如果不指定列的約束,默認(rèn)就是允許NULL,TIMESTAMP類型的字段除外。所以在非必要情況下,盡量設(shè)置列的約束為NOT NULL。
- 如果列的值為NULL,通過這個(gè)為NULL的列進(jìn)行條件查詢時(shí),MySQL更難做優(yōu)化,因?yàn)闉镹ULL的列會(huì)讓索引的統(tǒng)計(jì)和值的比較更加復(fù)雜。
- 如果計(jì)劃在某個(gè)列上創(chuàng)建索引,那么需要盡量避免這個(gè)列中的字段值為NULL。在優(yōu)化的過程中,把NULL改為NOT NULL對(duì)性能的提升并不是很明顯。所以如果在使用過程中沒有問題的話,沒有必要首先去做NULL到NOT NULL的優(yōu)化。
來通過實(shí)際例子看看最后一個(gè)問題。假如需要查詢上述test表中c1不為空的所有數(shù)據(jù),應(yīng)該使用"<> ‘’"呢?還是使用"IS NOT NULL"呢?測(cè)試結(jié)果如下:
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)
可以看到,不同的查詢條件,對(duì)于查詢的結(jié)果區(qū)別還是特別大的。所以在使用過程中需要根據(jù)業(yè)務(wù)場(chǎng)景,選擇不同的查詢條件。文章來源:http://www.zghlxwxcb.cn/news/detail-480488.html
附錄
附錄1:MySQL索引失效的常見情況
- 最左前綴原則。例如:存在聯(lián)合索引
idx_a_b(a, b)
,查詢條件使用where b = 1
則無法使用索引 - LIKE 前置模糊查詢。例如:
col_name like '%test'
或col_name like '%test%'
- 索引列使用函數(shù)或存在計(jì)算。例如:存在索引
idx_col(col)
,查詢條件使用where left(col, 2) = 'te'
- 查詢條件使用
is not null
。設(shè)計(jì)表結(jié)構(gòu)時(shí)盡量設(shè)置not null
約束 - 字段類型出現(xiàn)隱式轉(zhuǎn)換。例如:存在字段
test_col
為varchar
類型,查詢時(shí)使用了where test_col = 1
,隱式轉(zhuǎn)為了int
類型導(dǎo)致索引失效 - 條件中有 or 存在可能不會(huì)使用索引。例如:查詢條件為
where a = 'testa' or b = 'testb'
,存在索引idx_a(a)
,此時(shí)也不會(huì)使用索引,除非為b字段也添加索引 - 查詢結(jié)果超過整體結(jié)果的25%或三分之一,或者表數(shù)據(jù)量比較少時(shí),MySQL認(rèn)為全表掃描代價(jià)更小,會(huì)導(dǎo)致索引失效
附錄2:MySQL關(guān)鍵字列表
R 表示為 MySQL 預(yù)留關(guān)鍵字文章來源地址http://www.zghlxwxcb.cn/news/detail-480488.html
關(guān)鍵字 | 關(guān)鍵字 | 關(guān)鍵字 |
---|---|---|
ACCESSIBLE(R) | ACCOUNT | ACTION |
ADD(R) | AFTER | AGAINST |
AGGREGATE | ALGORITHM | ALL(R) |
ALTER(R) | ALWAYS | ANALYSE |
ANALYZE(R) | AND(R) | ANY |
AS(R) | ASC(R) | ASCII |
ASENSITIVE(R) | AT | AUTOEXTEND_SIZE |
AUTO_INCREMENT | AVG | AVG_ROW_LENGTH |
BACKUP | BEFORE(R) | BEGIN |
BETWEEN(R) | BIGINT(R) | BINARY(R) |
BINLOG | BIT | BLOB(R) |
BLOCK | BOOL | BOOLEAN |
BOTH(R) | BTREE | BY(R) |
BYTE | CACHE | CALL ? |
CASCADE ? | CASCADED | CASE ? |
CATALOG_NAME | CHAIN | CHANGE ? |
CHANGED | CHANNEL | CHAR ? |
CHARACTER ? | CHARSET | CHECK ? |
CHECKSUM | CIPHER | CLASS_ORIGIN |
CLIENT | CLOSE | COALESCE |
CODE | COLLATE ? | COLLATION |
COLUMN ? | COLUMNS | COLUMN_FORMAT |
COLUMN_NAME | COMMENT | COMMIT |
COMMITTED | COMPACT | COMPLETION |
COMPRESSED | COMPRESSION | CONCURRENT |
CONDITION ? | CONNECTION | CONSISTENT |
CONSTRAINT ? | CONSTRAINT_CATALOG | CONSTRAINT_NAME |
CONSTRAINT_SCHEMA | CONTAINS | CONTEXT |
CONTINUE ? | CONVERT ? | CPU |
CREATE ? | CROSS ? | CUBE |
CURRENT | CURRENT_DATE ? | CURRENT_TIME ? |
CURRENT_TIMESTAMP ? | CURRENT_USER ? | CURSOR ? |
CURSOR_NAME | DATA | DATABASE ? |
DATABASES ? | DATAFILE | DATE |
DATETIME | DAY | DAY_HOUR ? |
DAY_MICROSECOND ? | DAY_MINUTE ? | DAY_SECOND ? |
DEALLOCATE | DEC ? | DECIMAL ? |
DECLARE ? | DEFAULT ? | DEFAULT_AUTH |
DEFINER | DELAYED ? | DELAY_KEY_WRITE |
DELETE ? | DESC ? | DESCRIBE ? |
DES_KEY_FILE | DETERMINISTIC ? | DIAGNOSTICS |
DIRECTORY | DISABLE | DISCARD |
DISK | DISTINCT ? | DISTINCTROW ? |
DIV ? | DO | DOUBLE ? |
DROP ? | DUAL ? | DUMPFILE |
DUPLICATE | DYNAMIC | EACH ? |
ELSE ? | ELSEIF ? | ENABLE |
ENCLOSED ? | ENCRYPTION | END |
ENDS | ENGINE | ENGINES |
ENUM | ERROR | ERRORS |
ESCAPE | ESCAPED ? | EVENT |
EVENTS | EVERY | EXCHANGE |
EXECUTE | EXISTS ? | EXIT ? |
EXPANSION | EXPIRE | EXPLAIN ? |
EXPORT | EXTENDED | EXTENT_SIZE |
FALSE ? | FAST | FAULTS |
FETCH ? | FIELDS | FILE |
FILE_BLOCK_SIZE | FILTER | FIRST |
FIXED | FLOAT(R) | FLOAT4(R) |
FLOAT8(R) | FLUSH | FOLLOWS |
FOR(R) | FORCE(R) | FOREIGN(R) |
FORMAT | FOUND | FROM(R) |
FULL | FULLTEXT(R) | FUNCTION |
GENERAL | GENERATED(R) | GEOMETRY |
GEOMETRYCOLLECTION | GET(R) | GET_FORMAT |
GLOBAL | GRANT(R) | GRANTS |
GROUP(R) | GROUP_REPLICATION | HANDLER |
HASH | HAVING(R) | HELP |
HIGH_PRIORITY(R) | HOST | HOSTS |
HOUR | HOUR_MICROSECOND(R) | HOUR_MINUTE(R) |
HOUR_SECOND(R) | IDENTIFIED | IF(R) |
IGNORE(R) | IGNORE_SERVER_IDS | IMPORT |
IN(R) | INDEX(R) | INDEXES |
INFILE(R) | INITIAL_SIZE | INNER(R) |
INOUT(R) | INSENSITIVE(R) | INSERT(R) |
INSERT_METHOD | INSTALL | INSTANCE |
INT(R) | INT1(R) | INT2(R) |
INT3(R) | INT4(R) | INT8(R) |
INTEGER(R) | INTERVAL(R) | INTO(R) |
INVOKER | IO | IO_AFTER_GTIDS(R) |
IO_BEFORE_GTIDS(R) | IO_THREAD | IPC |
IS(R) | ISOLATION | ISSUER |
ITERATE(R) | JOIN(R) | JSON |
KEY(R) | KEYS(R) | KEY_BLOCK_SIZE |
KILL(R) | LANGUAGE | LAST |
LEADING(R) | LEAVE ? | LEAVES |
LEFT ? | LESS | LEVEL |
LIKE ? | LIMIT ? | LINEAR(R) |
LINES(R) | LINESTRING | LIST |
LOAD(R) | LOCAL | LOCALTIME(R) |
LOCALTIMESTAMP(R) | LOCK(R) | LOCKS |
LOGFILE | LOGS | LONG(R) |
LONGBLOB(R) | LONGTEXT(R) | LOOP(R) |
LOW_PRIORITY(R) | MASTER | MASTER_AUTO_POSITION |
MASTER_BIND(R) | MASTER_CONNECT_RETRY | MASTER_DELAY |
MASTER_HEARTBEAT_PERIOD | MASTER_HOST | MASTER_LOG_FILE |
MASTER_LOG_POS | MASTER_PASSWORD | MASTER_PORT |
MASTER_RETRY_COUNT | MASTER_SERVER_ID | MASTER_SSL |
MASTER_SSL_CA | MASTER_SSL_CAPATH | MASTER_SSL_CERT |
MASTER_SSL_CIPHER | MASTER_SSL_CRL | MASTER_SSL_CRLPATH |
MASTER_SSL_KEY | MASTER_SSL_VERIFY_SERVER_CERT(R) | MASTER_TLS_VERSION |
MASTER_USER | MATCH(R) | MAXVALUE(R) |
MAX_CONNECTIONS_PER_HOUR | MAX_QUERIES_PER_HOUR | MAX_ROWS |
MAX_SIZE | MAX_STATEMENT_TIME | MAX_UPDATES_PER_HOUR |
MAX_USER_CONNECTIONS | MEDIUM | MEDIUMBLOB(R) |
MEDIUMINT(R) | MEDIUMTEXT(R) | MEMORY |
MERGE | MESSAGE_TEXT | MICROSECOND |
MIDDLEINT(R) | MIGRATE | MINUTE |
MINUTE_MICROSECOND(R) | MINUTE_SECOND(R) | MIN_ROWS |
MOD(R) | MODE | MODIFIES(R) |
MODIFY | MONTH | MULTILINESTRING |
MULTIPOINT | MULTIPOLYGON | MUTEX |
MYSQL_ERRNO | NAME | NAMES |
NATIONAL | NATURAL(R) | NCHAR |
NDB | NDBCLUSTER | NEVER |
NEW | NEXT | NO |
NODEGROUP | NONBLOCKING | NONE |
NOT(R) | NO_WAIT | NO_WRITE_TO_BINLOG(R) |
NULL(R) | NUMBER | NUMERIC(R) |
NVARCHAR | OFFSET | OLD_PASSWORD |
ON(R) | ONE | ONLY |
OPEN | OPTIMIZE(R) | OPTIMIZER_COSTS(R) |
OPTION(R) | OPTIONALLY(R) | OPTIONS |
OR(R) | ORDER(R) | OUT(R) |
OUTER(R) | OUTFILE(R) | OWNER |
PACK_KEYS | PAGE | PARSER |
PARSE_GCOL_EXPR | PARTIAL | PARTITION(R) |
PARTITIONING | PARTITIONS | PASSWORD |
PHASE | PLUGIN | PLUGINS |
PLUGIN_DIR | POINT | POLYGON |
PORT | PRECEDES | PRECISION(R) |
PREPARE | PRESERVE | PREV |
PRIMARY(R) | PRIVILEGES | PROCEDURE(R) |
PROCESSLIST | PROFILE | PROFILES |
PROXY | PURGE(R) | QUARTER |
QUERY | QUICK | RANGE(R) |
READ(R) | READS(R) | READ_ONLY |
READ_WRITE(R) | REAL(R) | REBUILD |
RECOVER | REDOFILE | REDO_BUFFER_SIZE |
REDUNDANT | REFERENCES(R) | REGEXP(R) |
RELAY | RELAYLOG | RELAY_LOG_FILE |
RELAY_LOG_POS | RELAY_THREAD | RELEASE(R) |
RELOAD | REMOVE | RENAME(R) |
REORGANIZE | REPAIR | REPEAT(R) |
REPEATABLE | REPLACE(R) | REPLICATE_DO_DB |
REPLICATE_DO_TABLE | REPLICATE_IGNORE_DB | REPLICATE_IGNORE_TABLE |
REPLICATE_REWRITE_DB | REPLICATE_WILD_DO_TABLE | REPLICATE_WILD_IGNORE_TABLE |
REPLICATION | REQUIRE(R) | RESET |
RESIGNAL(R) | RESTORE | RESTRICT(R) |
RESUME | RETURN(R) | RETURNED_SQLSTATE |
RETURNS | REVERSE | REVOKE(R) |
RIGHT(R) | RLIKE(R) | ROLLBACK |
ROLLUP | ROTATE | ROUTINE |
ROW | ROWS | ROW_COUNT |
ROW_FORMAT | RTREE | SAVEPOINT |
SCHEDULE | SCHEMA(R) | SCHEMAS(R) |
SCHEMA_NAME | SECOND | SECOND_MICROSECOND(R) |
SECURITY | SELECT(R) | SENSITIVE(R) |
SEPARATOR(R) | SERIAL | SERIALIZABLE |
SERVER | SESSION | SET(R) |
SHARE | SHOW(R) | SHUTDOWN |
SIGNAL(R) | SIGNED | SIMPLE |
SLAVE | SLOW | SMALLINT(R) |
SNAPSHOT | SOCKET | SOME |
SONAME | SOUNDS | SOURCE |
SPATIAL ? | SPECIFIC ? | SQL ? |
SQLEXCEPTION ? | SQLSTATE ? | SQLWARNING ? |
SQL_AFTER_GTIDS | SQL_AFTER_MTS_GAPS | SQL_BEFORE_GTIDS |
SQL_BIG_RESULT(R) | SQL_BUFFER_RESULT | SQL_CACHE |
SQL_CALC_FOUND_ROWS(R) | SQL_NO_CACHE | SQL_SMALL_RESULT(R) |
SQL_THREAD | SQL_TSI_DAY | SQL_TSI_HOUR |
SQL_TSI_MINUTE | SQL_TSI_MONTH | SQL_TSI_QUARTER |
SQL_TSI_SECOND | SQL_TSI_WEEK | SQL_TSI_YEAR |
SSL(R) | STACKED | START |
STARTING(R) | STARTS | STATS_AUTO_RECALC |
STATS_PERSISTENT | STATS_SAMPLE_PAGES | STATUS |
STOP | STORAGE | STORED(R) |
STRAIGHT_JOIN(R) | STRING | SUBCLASS_ORIGIN |
SUBJECT | SUBPARTITION | SUBPARTITIONS |
SUPER | SUSPEND | SWAPS |
SWITCHES | TABLE(R) | TABLES |
TABLESPACE | TABLE_CHECKSUM | TABLE_NAME |
TEMPORARY | TEMPTABLE | TERMINATED(R) |
TEXT | THAN | THEN(R) |
TIME | TIMESTAMP | TIMESTAMPADD |
TIMESTAMPDIFF | TINYBLOB(R) | TINYINT(R) |
TINYTEXT(R) | TO(R) | TRAILING(R) |
TRANSACTION | TRIGGER ? | TRIGGERS |
TRUE ? | TRUNCATE | TYPE |
TYPES | UNCOMMITTED | UNDEFINED |
UNDO(R) | UNDOFILE | UNDO_BUFFER_SIZE |
UNICODE | UNINSTALL | UNION(R) |
UNIQUE(R) | UNKNOWN | UNLOCK(R) |
UNSIGNED(R) | UNTIL | UPDATE(R) |
UPGRADE | USAGE(R) | USE(R) |
USER | USER_RESOURCES | USE_FRM |
USING(R) | UTC_DATE(R) | UTC_TIME(R) |
UTC_TIMESTAMP(R) | VALIDATION | VALUE |
VALUES(R) | VARBINARY(R) | VARCHAR(R) |
VARCHARACTER(R) | VARIABLES | VARYING(R) |
VIEW | VIRTUAL(R) | WAIT |
WARNINGS | WEEK | WEIGHT_STRING |
WHEN(R) | WHERE(R) | WHILE(R) |
WITH(R) | WITHOUT | WORK |
WRAPPER | WRITE(R) | X509 |
XA | XID | XML |
XOR(R) | YEAR | YEAR_MONTH(R) |
ZEROFILL(R) |
到了這里,關(guān)于【MySQL】 IS NOT NULL 和 != NULL 的區(qū)別?的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!