MySQL运维实战(4.4) SQL_MODE之STRICT_TRANS_TABLES和STRICT_ALL_TABLES

俊达1年前技术文章635

如果设置STRICT模式,则如果数据写入时,如果数据不符合字段定义(字符串超出长度、数值类型数据超出范围、违反not null约束等),SQL会报错。

如果不设置STRICT模式,会对异常数据进行截断处理,SQL会显示Warning,但不报错。


对于组合型SQL,对于非事物型存储引擎,如MyISAM存储引擎,一个SQL中部分数据合法,部分数据不合法,则可能会在表中写入部分数据。


STRICT_ALL_TABLES

对于非事务型存储引擎如MyISAM,可能会出现批量Insert中部分数据写入成功、部分数据写入失败的情况。事务型存储引擎如InnoDB不存在该问题。

mysql> create table t_innodb(a int) engine=innodb;
Query OK, 0 rows affected (0.02 sec)

mysql> create table t_myisam(a int) engine=myisam;
Query OK, 0 rows affected (0.01 sec)

mysql> set sql_mode='STRICT_ALL_TABLES';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> insert into t_innodb values(1),('abc'),(3);
ERROR 1366 (HY000): Incorrect integer value: 'abc' for column 'a' at row 2

mysql> select * from t_innodb;
Empty set (0.00 sec)

mysql> insert into t_myisam values(1),('abc'),(3);
ERROR 1366 (HY000): Incorrect integer value: 'abc' for column 'a' at row 2

mysql> select * from t_myisam;
+------+
| a    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)


STRICT_TRANS_TABLES

如果设置strict_trans_tables SQL_MODE,则只影响事物型存储引擎。不影响往非事务型引擎中写入非法数据。

mysql> set sql_mode='STRICT_TRANS_TABLES';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> insert into t_innodb values(10),('abc'),(30);
ERROR 1366 (HY000): Incorrect integer value: 'abc' for column 'a' at row 2

mysql> insert into t_myisam values(10),('abc'),(30);
Query OK, 3 rows affected, 1 warning (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 1

mysql> show warnings;
+---------+------+--------------------------------------------------------+
| Level   | Code | Message                                                |
+---------+------+--------------------------------------------------------+
| Warning | 1366 | Incorrect integer value: 'abc' for column 'a' at row 2 |
+---------+------+--------------------------------------------------------+
1 row in set (0.01 sec)

mysql> select * from t_myisam;
+------+
| a    |
+------+
|    1 |
|   10 |
|    0 |
|   30 |
+------+
4 rows in set (0.00 sec)


不设置STRICT模式

不设置STRICT模式,则可以写入非法数据。SQL会有warning,非法的数据,会根据字段类型做相应的处理。

mysql> set sql_mode='';
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t_innodb values(100), ('abc');
Query OK, 2 rows affected, 1 warning (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 1

mysql> show warnings;
+---------+------+--------------------------------------------------------+
| Level   | Code | Message                                                |
+---------+------+--------------------------------------------------------+
| Warning | 1366 | Incorrect integer value: 'abc' for column 'a' at row 2 |
+---------+------+--------------------------------------------------------+
1 row in set (0.01 sec)

mysql> insert into t_myisam values(100), ('abc');
Query OK, 2 rows affected, 1 warning (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 1

mysql> show warnings;
+---------+------+--------------------------------------------------------+
| Level   | Code | Message                                                |
+---------+------+--------------------------------------------------------+
| Warning | 1366 | Incorrect integer value: 'abc' for column 'a' at row 2 |
+---------+------+--------------------------------------------------------+
1 row in set (0.00 sec)

mysql> select * from t_innodb;
+------+
| a    |
+------+
|  100 |
|    0 |
+------+
2 rows in set (0.00 sec)

mysql> select * from t_myisam;
+------+
| a    |
+------+
|    1 |
|   10 |
|    0 |
|   30 |
|  100 |
|    0 |
+------+
6 rows in set (0.00 sec)


字符串类型

字符串类型的处理方式是截断超出长度的字符

mysql> set sql_mode='STRICT_ALL_TABLES';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> create table t_str(a varchar(3));
Query OK, 0 rows affected (0.01 sec)

mysql> insert into t_str values('abcd');
ERROR 1406 (22001): Data too long for column 'a' at row 1

mysql> select * from t_str;
Empty set (0.00 sec)



mysql>  set sql_mode='';
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t_str values('abcd');
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> show warnings;
+---------+------+----------------------------------------+
| Level   | Code | Message                                |
+---------+------+----------------------------------------+
| Warning | 1265 | Data truncated for column 'a' at row 1 |
+---------+------+----------------------------------------+
1 row in set (0.00 sec)

mysql> select * from t_str;
+------+
| a    |
+------+
| abc  |
+------+
1 row in set (0.00 sec)

数值类型

对于unsigned类型,插入负数会转换成0。如果数字超过允许的最大值,则截断为最大值


mysql> set sql_mode='STRICT_ALL_TABLES';

mysql> create table t_unsigned(a tinyint unsigned);
Query OK, 0 rows affected (0.01 sec)

mysql> insert into t_unsigned values(-1);
ERROR 1264 (22003): Out of range value for column 'a' at row 1

mysql> insert into t_unsigned values(256);
ERROR 1264 (22003): Out of range value for column 'a' at row 1

mysql> select * from t_unsigned;
Empty set (0.00 sec)

mysql> set sql_mode='';

mysql> insert into t_unsigned values(-1);
Query OK, 1 row affected, 1 warning (0.01 sec)

mysql> show warnings;
+---------+------+--------------------------------------------+
| Level   | Code | Message                                    |
+---------+------+--------------------------------------------+
| Warning | 1264 | Out of range value for column 'a' at row 1 |
+---------+------+--------------------------------------------+
1 row in set (0.00 sec)

mysql> select * from t_unsigned;
+------+
| a    |
+------+
|    0 |
+------+
1 row in set (0.00 sec)

mysql> insert into t_unsigned values(256);
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> show warnings;
+---------+------+--------------------------------------------+
| Level   | Code | Message                                    |
+---------+------+--------------------------------------------+
| Warning | 1264 | Out of range value for column 'a' at row 1 |
+---------+------+--------------------------------------------+
1 row in set (0.00 sec)

mysql> select * from t_unsigned;
+------+
| a    |
+------+
|    0 |
|  255 |
+------+
2 rows in set (0.00 sec)


总结


建议设置STRICT_TRANS_TABLES。生产环境修改SQL_MODE需要先进行兼容性测试。


相关文章

MySQL运维实战(5.5) 数据导入导出时的字符集问题

mysql可以使用load data/select into outfile或mysqldump工具进行数据导入导出。下面分别分析数据导入导出时的字符集相关问题。准备测试数据创建测试表,2个字段分别使...

 MySQL运维实战之Clone插件(10.1)使用Clone插件

MySQL运维实战之Clone插件(10.1)使用Clone插件

clone插件介绍mysql 8.0.17版本引入了clone插件。使用clone插件可以对本地l或远程的mysql实例进行clone操作。clone插件会拷贝innodb存储引擎表,clone得到的...

MySQL运维实战之备份和恢复(8.8)恢复单表

xtrabackup支持单表恢复。如果一个表使用了独立表空间(innodb_file_per_table=1),就可以单独恢复这个表。1、Prepareprepare时带上参数--export,xtr...

 MySQL优化器特性(九)行数评估

MySQL优化器特性(九)行数评估

查询的行数在成本计算中起了很重要的作用:1、row_evaluate_cost和行数直接相关2、需要访问多少索引页面,和行数直接相关。根据页面大小和平均索引条目长度计算每个索引页面的记录数,根据记录数...

MySQL优化器特性(三)表关联之BKA(Batched Key Access)优化

MySQL优化器特性(三)表关联之BKA(Batched Key Access)优化

单表range查询时,可以使用MRR优化,先对rowid进行排序,然后再回表查询数据。在表关联的时候,也可以使用类似的优化方法,先根据关联条件取出被关联表的rowid,将rowid缓存在join bu...

MySQL运维实战之备份和恢复(8.3)xtrabackup增量备份

xtrabackup支持增量备份。在做增量备份之前,需要先做一个全量备份。xtrabackup会基于innodb page的lsn号来判断是否需要备份一个page。如果page lsn大于上次备份的l...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。