18.2.6. MySQL分区处理NULL值的方式

MySQL 中的分区在禁止空值(NULL)上没有进行处理,无论它是一个列值还是一个用户定义表达式的值。一般而言,在这种情况下MySQL NULL视为0。如果你希望回避这种做法,你应该在设计表时不允许空值;最可能的方法是,通过声明列“NOT NULL”来实现这一点。

在本节中,我们提供了一些例子,来说明当决定一个行应该保存到哪个分区时,MySQL 是如何处理NULL值的。

如果插入一行到按照RANGELIST分区的表,该行用来确定分区的列值为NULL,分区将把该NULL值视为0。例如,考虑下面的两个表,表的创建和插入记录如下:

mysql> CREATE TABLE tnlist (
    ->     id INT,
    ->     name VARCHAR(5)
    -> )
    -> PARTITION BY LIST(id) (
    ->     PARTITION p1 VALUES IN (0),
    ->     PARTITION p2 VALUES IN (1)
    -> );
Query OK, 0 rows affected (0.09 sec)
 
mysql> CREATE TABLE tnrange (
    ->     id INT,
    ->     name VARCHAR(5)
    -> )
    -> PARTITION BY RANGE(id) (
    ->     PARTITION p1 VALUES LESS THAN (1),
    ->     PARTITION p2 VALUES LESS THAN MAXVALUE
    -> );
Query OK, 0 rows affected (0.09 sec)
 
mysql> INSERT INTO tnlist VALUES (NULL, 'bob');
Query OK, 1 row affected (0.00 sec)
 
mysql> INSERT INTO tnrange VALUES (NULL, 'jim');
Query OK, 1 row affected (0.00 sec)
 
mysql> SELECT * FROM tnlist;
+------+------+
| id   | name |
+------+------+
| NULL | bob  |
+------+------+
1 row in set (0.00 sec)
 
mysql> SELECT * FROM tnrange;
+------+------+
| id   | name |
+------+------+
| NULL | jim  |
+------+------+
1 row in set (0.00 sec)

在两个表中,id列没有声明为“NOT NULL”,这意味着它们允许Null值。可以通过删除这些分区,然后重新运行SELECT 语句,来验证这些行被保存在每个表的p1分区中:

mysql> ALTER TABLE tnlist DROP PARTITION p1;
Query OK, 0 rows affected (0.16 sec)
 
mysql> ALTER TABLE tnrange DROP PARTITION p1;
Query OK, 0 rows affected (0.16 sec)
 
mysql> SELECT * FROM tnlist;
Empty set (0.00 sec)
 
mysql> SELECT * FROM tnrange;
Empty set (0.00 sec)

在按HASHKEY分区的情况下,任何产生NULL值的表达式都视同好像它的返回值为0。我们可以通过先创建一个按HASH分区的表,然后插入一个包含有适当值的记录,再检查对文件系统的作用,来验证这一点。假定有使用下面的语句在测试数据库中创建了一个表tnhash

CREATE TABLE tnhash (
    id INT,
    name VARCHAR(5)
)
PARTITION BY HASH(id)
PARTITIONS 2

假如Linux 上的MySQL 的一个RPM安装,这个语句在目录/var/lib/mysql/test创建了两个.MYD文件,这两个文件可以在bash shell中查看,结果如下:

/var/lib/mysql/test> ls *.MYD -l
-rw-rw----  1 mysql mysql 0 2005-11-04 18:41 tnhash_p0.MYD
-rw-rw----  1 mysql mysql 0 2005-11-04 18:41 tnhash_p1.MYD

注意:每个文件的大小为0字节。现在在表tnhash 中插入一行id列值为NULL的行,然后验证该行已经被插入:

mysql> INSERT INTO tnhash VALUES (NULL, 'sam');
Query OK, 1 row affected (0.00 sec)
 
mysql> SELECT * FROM tnhash;
+------+------+
| id   | name |
+------+------+
| NULL | sam  |
+------+------+
1 row in set (0.01 sec)

回想一下,对于任意的整数N,NULL MOD N 的值总是等于NULL。这个结果在确定正确的分区方面被认为是0。回到系统shell(仍然假定bash用于这个目的) ,通过再次列出数据文件,可以看出值被成功地插入到第一个分区(默认名称为p0)中:

var/lib/mysql/test> ls *.MYD -l
-rw-rw----  1 mysql mysql 20 2005-11-04 18:44 tnhash_p0.MYD
-rw-rw----  1 mysql mysql  0 2005-11-04 18:41 tnhash_p1.MYD

可以看出INSERT语句只修改了文件tnhash_p0.MYD,它在磁盘上的尺寸增加了,而没有影响其他的文件。

假定有下面的一个表:

CREATE TABLE tndate (
    id INT,
    dt DATE
)
PARTITION BY RANGE( YEAR(dt) ) (
    PARTITION p0 VALUES LESS THAN (1990),
    PARTITION p1 VALUES LESS THAN (2000),
    PARTITION p2 VALUES LESS THAN MAXVALUE
)

像其他的MySQL函数一样,YEAR(NULL)返回NULL值。一个dt列值为NULL的行,其分区表达式的计算结果被视为0,该行被插入到分区p0中。

关注编程学问公众号