MySQL的数据类型介绍

一、整型

类型 存储空(单位:字节) 取值区间(有符号) 取值区间(无符号)
tinyint 1 [ -128,127 ] [0,255]
smallint 2 [-32768 , 32767] [0,65535]
mediumint 3 [-8388608 , 8388607] [0 , 16777215]
int 4 [-2147483648 , 2147483647] [0 , 4294967295]
bigint 8 [ -9223372036854775808 , 9223372036854775807] [0 , 18446744073709551615]

1.INT类型使用建议

  • 推荐不使用unsigned
  • 自增int类型主键建议使用bigint

2.unsigned的注意事项

mysql> create table test_unsigned(a int unsigned, b int unsigned);
Query OK, 0 rows affected (0.04 sec)

mysql> insert into test_unsigned values(1, 2);
Query OK, 1 row affected (0.01 sec)

//注意这个地方就报错了!
mysql> select a - b from test_unsigned;
ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '(`test`.`test_unsigned`.`a` - `test`.`test_unsigned`.`b`)'
mysql> select b-a from test_unsigned;
+------+
| b-a  |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

// 这样可以得到负数
mysql> set sql_mode = 'no_unsigned_subtraction';
Query OK, 0 rows affected, 1 warning (0.00 sec)

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

3.zerofill的注意事项

对于INT(N)来说,N无论写成多大,都是占4个字节的空间,而非写成几就能存几位 N不是带代表能存多少位,只是显示宽度。例如 INT(4) 和 INT(10)其实存的东西是一样的长度。 zerofill 表示当存储的数字长度 < N 时,用数字0 填充左边,直至补满长度N 当存储数字的长度超过N时,按照实际存储的数字显示 int(N)中的N 和zerofill 配合才有意义,且仅仅是显示的时候才有意义,和实际存储没有关系,不会去截取数字的长度。

mysql> create table test_int_n(a int(3) zerofill);
Query OK, 0 rows affected (0.03 sec)

//不满 N=3时,左边用0填充
mysql> insert into test_int_n values(1);
Query OK, 1 row affected (0.01 sec)
mysql> select * from test_int_n;
+------+
| a    |
+------+
|  001 |
+------+
1 row in set (0.00 sec)

//超过N=3的长度时,是什么数字,就显示什么数字
mysql> insert into test_int_n values(1111);
Query OK, 1 row affected (0.00 sec)
mysql> select * from test_int_n;
+------+
| a    |
+------+
|  001 |
| 1111 |
+------+
2 rows in set (0.00 sec)

//
mysql> select a, HEX(a) from test_int_n;
+------+--------+
| a    | HEX(a) |
+------+--------+
|  001 | 1      |   -- 实际存储的还是1
| 1111 | 457    |   -- 1111对于的16进制就是457
+------+--------+
2 rows in set (0.00 sec)

4.auto_increment

自增,每张表最多一个,必须是索引的一部分

//没有指定key,创建的时候就会报错
mysql> create table test_auto_increment(a int auto_increment);
ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key

//指定了key,则创建成功
mysql> create table test_auto_increment(a int auto_increment primary key);
Query OK, 0 rows affected (0.02 sec)

//插入null,意思就是自增开始,从1开始
mysql> insert into test_auto_increment values(NULL);
Query OK, 1 row affected (0.01 sec)

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

//插入0,自增为2
mysql> insert into test_auto_increment values(0);
Query OK, 1 row affected (0.01 sec)

mysql> select * from test_auto_increment;
+---+
| a |
+---+
| 1 |
| 2 |
+---+
2 rows in set (0.00 sec)

//插入-1,则为-1
mysql> insert into test_auto_increment values(-1);
Query OK, 1 row affected (0.01 sec)

mysql> select * from test_auto_increment;
+----+
| a  |
+----+
| -1 |
|  1 |
|  2 |
+----+
3 rows in set (0.00 sec)

//插入null,继续从目前最大的值开始自增,从2开始
mysql> insert into test_auto_increment values(NULL);
Query OK, 1 row affected (0.00 sec)

mysql> select * from test_auto_increment;
+----+
| a  |
+----+
| -1 |
|  1 |
|  2 |
|  3 |
+----+
4 rows in set (0.00 sec)

//再次插入-1 ,报错,说明-1是直接插入值,而非使用自增
mysql> insert into test_auto_increment values(-1);
ERROR 1062 (23000): Duplicate entry '-1' for key 'PRIMARY'
mysql> insert into test_auto_increment values('0');
Query OK, 1 row affected (0.00 sec)

mysql> select * from test_auto_increment;
+----+
| a  |
+----+
| -1 |
|  1 |
|  2 |
|  3 |
|  4 |
+----+
5 rows in set (0.00 sec)

//这个是一个将自增从0开始的办法,先插入-1,再把 -1 update为 0
mysql> update test_auto_increment set a = 0 where a = -1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from test_auto_increment;
+---+
| a |
+---+
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
+---+
5 rows in set (0.00 sec)

//插入3个值,第一个是从4开始自增所以为5,第二个是直接插入100,第三个是从100开始自增所以为101
mysql> insert into test_auto_increment values(NULL), (100), (NULL);
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from test_auto_increment;
+-----+
| a   |
+-----+
|   0 |
|   1 |
|   2 |
|   3 |
|   4 |
|   5 |
| 100 |
| 101 |
+-----+
8 rows in set (0.00 sec)

//插入99,因为没有99这个值,所以直接插入进去
mysql> insert into test_auto_increment values(99);
Query OK, 1 row affected (0.00 sec)

mysql> select * from test_auto_increment;
+-----+
| a   |
+-----+
|   0 |
|   1 |
|   2 |
|   3 |
|   4 |
|   5 |
|  99 |
| 100 |
| 101 |
+-----+
9 rows in set (0.00 sec)

注意:

  1. AUTO_INCREMENT 是实例启动时,取当前表的最大值,然后 +1 即为下次自增的值。(MAX + 1)
    1. 数字 0 这个值比较特殊, 插入0和插入NULL的效果是一样的,都是代表自增
    2. insert into tablename select NULL; 等价于insert into tablename values (NULL);

二、浮点型

类型 占用空间 精度 精确性
float 4 单精度
double 8 双精度
decimal 变长 高精度 非常高
  • M*G/G 不一定=M
  • float(M,D) double(M,D) decimal(M,D) 表示显示M位整数,其中D位位于小数点后面

避免使用浮点类型,因为它并不属于精确的类型。 在生产环境中,不建议使用float和double,对于财务系统或者说和钱有关的,必须使用decimal。 即使使用了decimal,但是在数值运算中还是会转成浮点来运算,而且在计算过程中会出现四舍五入的情况。

//创建一个含有decimal类型的表
mysql> show create table test_decimal \G
*************************** 1. row ***************************
       Table: test_decimal
Create Table: CREATE TABLE `test_decimal` (
  `id` int(10) NOT NULL,
  `salary` decimal(6,2) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

//插入一个超过范围的6位的数,在表的定义写的是decimal(6,2),代表一共6位数,其中有2位为小数
//在5.7版本可用插入,但会有waring提示;在5.6版本直接报错
//查看插入的结果,就是最接近123456的一个数
mysql> insert into test_decimal(id,salary) values(1,123456);
Query OK, 1 row affected, 1 warning (0.01 sec)

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

mysql> select * from test_decimal;
+----+---------+
| id | salary  |
+----+---------+
|  1 | 9999.99 |
+----+---------+
1 row in set (0.00 sec)

//插入一个不超过范围的数,则正常显示
mysql> insert into test_decimal(id,salary) values(1,1234);
Query OK, 1 row affected (0.01 sec)

mysql> select * from test_decimal;
+----+---------+
| id | salary  |
+----+---------+
|  1 | 9999.99 |
|  1 | 1234.00 |
+----+---------+
2 rows in set (0.00 sec)

//插入一个小数超范围的数,则会四舍五入
mysql> insert into test_decimal(id,salary) values(1,1234,5678);
ERROR 1136 (21S01): Column count doesn't match value count at row 1
mysql> insert into test_decimal(id,salary) values(1,1234.5678);
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> select * from test_decimal;
+----+---------+
| id | salary  |
+----+---------+
|  1 | 9999.99 |
|  1 | 1234.00 |
|  1 | 1234.57 |
+----+---------+
3 rows in set (0.00 sec)

三、字符串类型

说明 N的含义 是否有字符集 最大长度
CHAR(N) 定长字符 字符 255
VARCHAR(N) 变长字符 字符 16384
BINARY(N) 定长二进制字节 字节 255
VARBINARY(N) 变长二进制字节 字节 16384
TINYBLOB 二进制大对象 字节 256
BLOB 二进制大对象 字节 16K
MEDIUMBLOB 二进制大对象 字节 16M
LONGBLOB 二进制大对象 字节 4G
TINYTEXT 大对象 字节 256
TEXT 大对象 字节 16K
MEDIUMTEXT 大对象 字节 16M
LONGTEXT 大对象 字节 4G

BLOB=>VARBINARY TEXT=>VARCHAR

注意事项 1.在BLOB和TEXT列上创建索引的时候,必须指定索引前缀的长度 2.varchar和varbinary前缀长度是可选的 3.blob和te列不能有默认值 4.blob和text列排序时只使用该列的前 max_sort_length个字节

1.char(N)说明

假设当前table的字符集的最大长度为W , 则char(N) 的最大存储空间为(N * W)Byte 假设使用UTF-8 ,则char(10)可以最小存储10个字节的字符,最大存储30个字节的字符,其实是另一种意义上的varchar 当存储的字符数小于N 时,尾部使用空格填充,并且填充最小字节的空格

mysql> create table test_char(a char(10));
Query OK, 0 rows affected (0.02 sec)

mysql> show create table test_char\G
*************************** 1. row ***************************
       Table: test_char
Create Table: CREATE TABLE `test_char` (
  `a` char(10) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

mysql> insert into test_char values('abc');
Query OK, 1 row affected (0.01 sec)

mysql> insert into test_char values('启明星');
Query OK, 1 row affected (0.01 sec)

mysql> insert into test_char values('启明星hh');
Query OK, 1 row affected (0.00 sec)

mysql> insert into test_char values('启明hh星');
Query OK, 1 row affected (0.00 sec)

mysql> insert into test_char values('启明hh星啊');
Query OK, 1 row affected (0.01 sec)

mysql> select a, length(a) from test_char;
+----------------+-----------+
| a              | length(a) |
+----------------+-----------+
| abc            |         3 |
| 启明星         |         9 |
| 启明星hh       |        11 |
| 启明hh星       |        11 |
| 启明hh星啊     |        14 |
+----------------+-----------+
5 rows in set (0.01 sec)

mysql> select a, hex(a) from test_char;
+----------------+------------------------------+
| a              | hex(a)                       |
+----------------+------------------------------+
| abc            | 616263                       |
| 启明星         | E590AFE6988EE6989F           |
| 启明星hh       | E590AFE6988EE6989F6868       |
| 启明hh星       | E590AFE6988E6868E6989F       |
| 启明hh星啊     | E590AFE6988E6868E6989FE5958A |
+----------------+------------------------------+
5 rows in set (0.00 sec)

mysql> select hex(' ');
+----------+
| hex(' ') |
+----------+
| 20       |
+----------+
1 row in set (0.00 sec)

用hexdump来比较一下:

-- 1:abc
-- 2:启明星
-- 3:启明星hh
-- 4:启明hh星
-- 5:启明ab星啊
[root@nazeebo test]# hexdump -C test_char.ibd
...
...
00006070  73 75 70 72 65 6d 75 6d  0a 00 00 00 10 00 24 00  |supremum......$.|
00006080  00 00 00 02 07 00 00 00  00 0a b5 fe 00 00 00 48  |...............H|
00006090  01 10 61 62 63 20 20 20  20 20 20 20 0a 00 00 00  |..abc       ....|
000060a0  18 00 24 00 00 00 00 02  08 00 00 00 00 0a b6 ff  |..$.............|
000060b0  00 00 00 4c 01 10 e5 90  af e6 98 8e e6 98 9f 20  |...L........... |
000060c0  0b 00 00 00 20 00 25 00  00 00 00 02 09 00 00 00  |.... .%.........|
000060d0  00 0a bb a2 00 00 00 4d  01 10 e5 90 af e6 98 8e  |.......M........|
000060e0  e6 98 9f 68 68 0b 00 00  00 28 00 25 00 00 00 00  |...hh....(.%....|
000060f0  02 0a 00 00 00 00 0a bc  a3 00 00 00 49 01 10 e5  |............I...|
00006100  90 af e6 98 8e 68 68 e6  98 9f 0e 00 00 00 30 ff  |.....hh.......0.|
00006110  5f 00 00 00 00 02 0b 00  00 00 00 0a c1 a6 00 00  |_...............|
00006120  00 4a 01 10 e5 90 af e6  98 8e 68 68 e6 98 9f e5  |.J........hh....|
00006130  95 8a 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00006140  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
...
省略一部分输出
...
[root@nazeebo test]#

2.varchar(N)说明

mysql> create table test_varchar(a varchar(10));
Query OK, 0 rows affected (0.03 sec)

mysql> show create table test_varchar \G
*************************** 1. row ***************************
       Table: test_varchar
Create Table: CREATE TABLE `test_varchar` (
  `a` varchar(10) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

mysql> insert into test_varchar values('abc');
Query OK, 1 row affected (0.00 sec)

mysql> insert into test_varchar values('启明星');
Query OK, 1 row affected (0.01 sec)

mysql> insert into test_varchar values('启明星hh');
Query OK, 1 row affected (0.01 sec)

mysql> insert into test_varchar values('启明hh星');
Query OK, 1 row affected (0.01 sec)

mysql> insert into test_varchar values('启明hh星啊');
Query OK, 1 row affected (0.01 sec)

mysql> select a, hex(a) from test_varchar;
+----------------+------------------------------+
| a              | hex(a)                       |
+----------------+------------------------------+
| abc            | 616263                       |
| 启明星         | E590AFE6988EE6989F           |
| 启明星hh       | E590AFE6988EE6989F6868       |
| 启明hh星       | E590AFE6988E6868E6989F       |
| 启明hh星啊     | E590AFE6988E6868E6989FE5958A |
+----------------+------------------------------+
5 rows in set (0.01 sec)

mysql> select a, length(a) from test_varchar;
+----------------+-----------+
| a              | length(a) |
+----------------+-----------+
| abc            |         3 |
| 启明星         |         9 |
| 启明星hh       |        11 |
| 启明hh星       |        11 |
| 启明hh星啊     |        14 |
+----------------+-----------+
5 rows in set (0.00 sec)
[root@nazeebo test]# hexdump -C test_varchar.ibd
...
...
00006070  73 75 70 72 65 6d 75 6d  03 00 00 00 10 00 1d 00  |supremum........|
00006080  00 00 00 02 0c 00 00 00  00 0a c6 ab 00 00 00 51  |...............Q|
00006090  01 10 61 62 63 09 00 00  00 18 00 23 00 00 00 00  |..abc......#....|
000060a0  02 0d 00 00 00 00 0a c7  ac 00 00 00 4c 01 10 e5  |............L...|
000060b0  90 af e6 98 8e e6 98 9f  0b 00 00 00 20 00 25 00  |............ .%.|
000060c0  00 00 00 02 0e 00 00 00  00 0a cc af 00 00 00 4d  |...............M|
000060d0  01 10 e5 90 af e6 98 8e  e6 98 9f 68 68 0b 00 00  |...........hh...|
000060e0  00 28 00 25 00 00 00 00  02 0f 00 00 00 00 0a cd  |.(.%............|
000060f0  b0 00 00 00 4b 01 10 e5  90 af e6 98 8e 68 68 e6  |....K........hh.|
00006100  98 9f 0e 00 00 00 30 ff  67 00 00 00 00 02 10 00  |......0.g.......|
00006110  00 00 00 0a d2 b3 00 00  00 4c 01 10 e5 90 af e6  |.........L......|
00006120  98 8e 68 68 e6 98 9f e5  95 8a 00 00 00 00 00 00  |..hh............|
00006130  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
...
...

3.char和varchar的区别

char用于定长,范围0-255,如果字符数没有到达定义的长度,会在后面用空格补全存入数据库;如果超过指定长度大小,会被截断。 varchar用于变长,范围0-65535,存储时按大小存取不会补空格,超过长度会截取。 使用varchar类型时,和字符集有关,会多用1~2个字节来记录字节长度,当数据位战友的字节数小于255时,用1个字节来记录长度,当数据位战友的字节数大于255时,用2个字节来记录长度,另外一位用来记录是否为null值

MySQL每一行的最大字节数为65535 使用UTF8字符集的时候,每个字符最多占3个字节,最大长度不超过(65535-2-1)/3=21844 使用GBK字符集的时候,每个字符最多占用2个字节,最大长度不超(65535-2-1)/ 2 = 36766

4.BLOB和TEXT

在BLOB和TEXT上创建索引时,必须指定索引前缀的长度

mysql> create table test_text(a int primary key, b text, key(b));
ERROR 1170 (42000): BLOB/TEXT column 'b' used in key specification without a key length
mysql> create table test_text(a int primary key, b text, key(b(64)));
Query OK, 0 rows affected (0.02 sec)

mysql> select @@max_sort_length;
+-------------------+
| @@max_sort_length |
+-------------------+
|              1024 |
+-------------------+
1 row in set (0.00 sec)

mysql>

BLOB和TEXT列不能有默认值 BLOB和TEXT列排序时只使用该列的前max_sort_length个字节

四、集合类型enum 和 set

enum允许最多65536个值 set允许最多64个值 通过sql_mode进行约束

1.集合的插入

//创建一个表,含有enum类型,插入几条数据
//虽然enum写的是字符串,单其实存储的整型,效率还行
mysql> create table test_col(
    -> user varchar(10),
    -> sex enum('male','female')
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql> insert into test_col values ("tom", "male");
Query OK, 1 row affected (0.00 sec)

//插入错误的enum,会有warings,并且相应的值被截断直接为空
mysql> insert into test_col values ("tom", "xmale");
Query OK, 1 row affected, 1 warning (0.01 sec)

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

mysql> select * from test_col;
+------+------+
| user | sex  |
+------+------+
| tom  | male |
| tom  |      |
+------+------+
2 rows in set (0.00 sec)

//设置sql_mode,发现错误的enum类型是插入不进去的
mysql> set sql_mode='strict_trans_tables';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> insert into test_col values ("bob", "xmale");
ERROR 1265 (01000): Data truncated for column 'sex' at row 1
mysql> select * from test_col;
+------+------+
| user | sex  |
+------+------+
| tom  | male |
| tom  |      |
+------+------+
2 rows in set (0.00 sec)

建议业务上都设置成严格模式 另外,虽然enum写的是字符串,单其实存储的是int类型数组(相当于male=0,female=1),性能还是可以的

2.集合的排序

mysql> show create table test_col_sort\G
*************************** 1. row ***************************
       Table: test_col_sort
Create Table: CREATE TABLE `test_col_sort` (
  `user` char(10) DEFAULT NULL,
  `type` enum('aaa','zzz','bbb','yyy','fff') DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

//插入数据
mysql> insert into test_col_sort(user,type) values('user1','aaa'),('user2','bbb'),('user3','yyy'),('user4','zzz');
Query OK, 4 rows affected (0.01 sec)
Records: 4  Duplicates: 0  Warnings: 0

//order by type 就等于按照enum里面的顺序,[0,1,2,3]
mysql> select * from test_col_sort order by type asc;
+-------+------+
| user  | type |
+-------+------+
| user1 | aaa  |
| user4 | zzz  |
| user2 | bbb  |
| user3 | yyy  |
+-------+------+
4 rows in set (0.00 sec)

//order by  cast(type as char) ,意思是将type转换为char再进行排序
mysql> select * from test_col_sort order by cast(type as char) asc;
+-------+------+
| user  | type |
+-------+------+
| user1 | aaa  |
| user2 | bbb  |
| user3 | yyy  |
| user4 | zzz  |
+-------+------+
4 rows in set (0.00 sec)

//order by concat
mysql> select * from test_col_sort order by concat(type) asc;
+-------+------+
| user  | type |
+-------+------+
| user1 | aaa  |
| user2 | bbb  |
| user3 | yyy  |
| user4 | zzz  |
+-------+------+
4 rows in set (0.00 sec)

五、日期类型

日期类型 占用字节 表示范围
DATETIME 8 1000-01-01 00:00:00 ~ 9999-12-31 23:59:59
DATE 3 1000-01-01 ~ 9999-12-31
TIMESTAMP 4 1970-01-01 00:00:00UTC ~ 2038-01-19 03:14:07UTC
YEAR 1 YEAR(2):1970-2070, YEAR(4):1901-2155
TIME 3 -838:59:59 ~ 838:59:59

1.TIMESTAMP 和 DATETIME

datetime与timestamp最大的区别在于时区

mysql> create table test_time(a timestamp, b datetime);
Query OK, 0 rows affected (0.02 sec)

mysql> insert into test_time values (now(), now());
Query OK, 1 row affected (0.01 sec)

mysql> select * from test_time;
+---------------------+---------------------+
| a                   | b                   |
+---------------------+---------------------+
| 2018-06-29 00:28:40 | 2018-06-29 00:28:40 |
+---------------------+---------------------+
1 row in set (0.00 sec)

mysql> select @@time_zone;
+-------------+
| @@time_zone |
+-------------+
| SYSTEM      |
+-------------+
1 row in set (0.00 sec)

mysql> set time_zone='+00:00';
Query OK, 0 rows affected (0.00 sec)

mysql> select @@time_zone;
+-------------+
| @@time_zone |
+-------------+
| +00:00      |
+-------------+
1 row in set (0.00 sec)

//设置了时区后,两者有了差别
mysql> select * from test_time;
+---------------------+---------------------+
| a                   | b                   |
+---------------------+---------------------+
| 2018-06-28 16:28:40 | 2018-06-29 00:28:40 |
+---------------------+---------------------+
1 row in set (0.00 sec)

2.微秒解读

MySQL5.6.4版本开始支持微秒 支持类型包括:time 、datetime与 、timestamp type_name(fsp) fsp<=6

//用法 type_name(fsp)  fsp<=6
mysql> select now(5);
+---------------------------+
| now(5)                    |
+---------------------------+
| 2018-06-28 16:34:10.64251 |
+---------------------------+
1 row in set (0.00 sec)

mysql> select now(6);
+----------------------------+
| now(6)                     |
+----------------------------+
| 2018-06-28 16:34:36.658036 |
+----------------------------+
1 row in set (0.00 sec)

// 最多支持6位精度
mysql> select now(7);
ERROR 1426 (42000): Too-big precision 7 specified for 'now'. Maximum is 6.
mysql>
mysql> create table test_time_fac (t datetime(6));
Query OK, 0 rows affected (0.02 sec)

mysql> insert into test_time_fac values(now(6));
Query OK, 1 row affected (0.01 sec)

mysql> select * from test_time_fac;
+----------------------------+
| t                          |
+----------------------------+
| 2018-06-28 16:35:04.557430 |
+----------------------------+
1 row in set (0.00 sec)

3.日期函数

函数 说明 备注
NOW 返回sql执行时的时间 如果不考虑其他因素,可以理解为写完SQL,敲下回车瞬间的时间
current_timestamp 与now一样
sysdate 返回执行函数时的时间 MySQL处理你的函数时的时间,统一SQL语句中,大于NOW
date_add(date,interval expr unit) 增加时间 可用ADD,然后unit给负数
date_sub(date,interval expr unit) 减少时间
date_format 格式化时间显示

3.1 NOW 和 SYSDATE的区别

mysql> select now(6),sysdate(6),sleep(5),now(6),sysdate(6);
+----------------------------+----------------------------+----------+----------------------------+----------------------------+
| now(6)                     | sysdate(6)                 | sleep(5) | now(6)                     | sysdate(6)                 |
+----------------------------+----------------------------+----------+----------------------------+----------------------------+
| 2018-06-29 00:38:59.002591 | 2018-06-29 00:38:59.002708 |        0 | 2018-06-29 00:38:59.002591 | 2018-06-29 00:39:04.002832 |
+----------------------------+----------------------------+----------+----------------------------+----------------------------+
1 row in set (5.00 sec)

两个now(6)都相等,因为是SQL执行时的时间(可以简单理解为按回车的时间) 两个sysdate(6)差了5秒,差不多刚好是sleep(5)的时间

3.2 date_add的使用方法

//加5天
mysql> select now(),date_add(now(), interval 5 day);
+---------------------+---------------------------------+
| now()               | date_add(now(), interval 5 day) |
+---------------------+---------------------------------+
| 2018-06-29 00:41:03 | 2018-07-04 00:41:03             |
+---------------------+---------------------------------+
1 row in set (0.00 sec)

//加负的5个月=倒退5个月
mysql> select now(),date_add(now(), interval -5 month);
+---------------------+------------------------------------+
| now()               | date_add(now(), interval -5 month) |
+---------------------+------------------------------------+
| 2018-06-29 00:41:28 | 2018-01-29 00:41:28                |
+---------------------+------------------------------------+
1 row in set (0.00 sec)

//减5个月
mysql> select now(),date_sub(now(), interval 5 month);
+---------------------+-----------------------------------+
| now()               | date_sub(now(), interval 5 month) |
+---------------------+-----------------------------------+
| 2018-06-29 00:41:43 | 2018-01-29 00:41:43               |
+---------------------+-----------------------------------+
1 row in set (0.00 sec)

3.3 date_format的用法

mysql> SELECT now(),DATE_FORMAT((select now(6)), '%H:%i:%s');
+---------------------+------------------------------------------+
| now()               | DATE_FORMAT((select now(6)), '%H:%i:%s') |
+---------------------+------------------------------------------+
| 2018-06-29 00:44:46 | 00:44:46                                 |
+---------------------+------------------------------------------+
1 row in set (0.00 sec)

3.4 字段更新时间

mysql> create table test_field_update(
    -> a int(10),
    -> b timestamp not null default current_timestamp on update current_timestamp
    -> );
Query OK, 0 rows affected (0.03 sec)

mysql> insert into test_field_update values(1, now(6));
Query OK, 1 row affected (0.00 sec)

mysql> select * from test_field_update;
+------+---------------------+
| a    | b                   |
+------+---------------------+
|    1 | 2018-06-29 00:45:46 |
+------+---------------------+
1 row in set (0.00 sec)

//更新数据,发现相应的字段的数据也更新了,这个可以拿来用在记录记录的表更上
//当然,如果想更精确,可以使用timestamp,now(6)
mysql> update test_field_update set a=100 where a=1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from test_field_update;
+------+---------------------+
| a    | b                   |
+------+---------------------+
|  100 | 2018-06-29 00:46:01 |
+------+---------------------+
1 row in set (0.00 sec)

六、JSON类型

  • 5.7版本开始支持
  • 原生json类型用来替代BLOB
  • json数据有效性检查:blob类型无法在数据库层做这样的约束性检查,而json类型可以
  • 查询性能的提升:查询不需要遍历所有的字符串才能找到数据
  • 支持部分属性索引:通过虚拟列的功能可以对json中的部分数据进行索引

1.JSON格式示例(wiki百科)

{
    "firstName": "John",  //Key: Value 格式
    "lastName": "Smith",
    "sex": "male",
    "age": 25,
    "address": //Key: Value;其中 Value 也是一个 Key - Value 的结构
    {
        "streetAddress": "21 2nd Street",
        "city": "New York",
        "state": "NY",
        "postalCode": "10021"
    },
    "phoneNumber": [{
            "type": "home",
            "number": "212 555-1234"
        },
        {
            "type": "fax",
            "number": "646 555-4567"
        }
    ]
}

2. JSON 和 BLOB 的对比

  • JSON:

    • JSON数据可以做有效性检查;
    • JSON使得查询性能提升;
    • JSON支持部分属性索引,通过虚拟列的功能可以对JSON中的部分数据进行索引;
  • BLOB:

    • BLOB类型无法在数据库层做约束性检查;
    • BLOB进行查询,需要遍历所有字符串;
    • BLOB做只能做指定长度的索引;
  • 5.7之前,只能把JSON当作BLOB进行存储。数据库层面无法对JSON数据做一些操作,只能由应用程序处理。

3. 结构化和非结构化

  • 结构化
    • 二维表结构(行和列)
    • 使用SQL语句进行操作
  • 非结构化
    • 使用Key-Value格式定义数据,无结构定义
    • Value可以嵌套Key-Value格式的数据
    • 使用JSON进行实现

4. json示例

mysql> create table test_json (
    -> uid int auto_increment,
    -> data json,
    -> primary key(uid)
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql>
mysql> insert into test_json values (
    -> null, -- 自增长数据,可以插入null
    -> '{
    '> "name":"nazeebo",
    '> "age":38,
    '> "address":"CD"
    '> }'
    -> );
Query OK, 1 row affected (0.00 sec)

mysql> insert into test_json values (
    -> null,
    -> '{
    '> "name":"lowa",
    '> "age":37,
    '> "mail":"lowa@bxbb.com"
    '> }'
    -> );
Query OK, 1 row affected (0.00 sec)

// 无法插入,因为是JSON类型
mysql> insert into test_json values ( null, "今晚打老虎");
ERROR 3140 (22032): Invalid JSON text: "Invalid value." at position 0 in value for column 'test_json.data'.
mysql>
mysql> select * from test_json;
+-----+------------------------------------------------------+
| uid | data                                                 |
+-----+------------------------------------------------------+
|   1 | {"age": 38, "name": "nazeebo", "address": "CD"}      | //这个json中有address字段
|   2 | {"age": 37, "mail": "lowa@bxbb.com", "name": "lowa"} | //这个json中有mail字段
+-----+------------------------------------------------------+
2 rows in set (0.00 sec)

mysql>

5. json的相关函数

5.1 使用json_extract提取数据

mysql> select json_extract('[10, 20, [30, 40]]', '$[1]');
+--------------------------------------------+
| json_extract('[10, 20, [30, 40]]', '$[1]') |
+--------------------------------------------+
| 20                                         |  // 从list中抽取 下标 为1的元素(下标从0开始)
+--------------------------------------------+
1 row in set (0.00 sec)

mysql> select
    -> json_extract(data, '$.name'), -- 提起name字段的数据
    -> json_extract(data, '$.address') -- 提取address字段的数据
    -> from test_json;
+------------------------------+---------------------------------+
| json_extract(data, '$.name') | json_extract(data, '$.address') |
+------------------------------+---------------------------------+
| "nazeebo"                    | "CD"                            |
| "lowa"                       | NULL                            |  // lowa 没有address字段,填充了NULL
+------------------------------+---------------------------------+
2 rows in set (0.00 sec)

5.2 使用json_object 将list(K-V对)封装成json格式

mysql> select json_object("name", "lm", "email", "limin@bxbb.com", "age",99);
+----------------------------------------------------------------+
| json_object("name", "lm", "email", "limin@bxbb.com", "age",99) |
+----------------------------------------------------------------+
| {"age": 99, "name": "lm", "email": "limin@bxbb.com"}           |
+----------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> insert into test_json values (
    -> null,
    -> json_object("name", "lm", "email", "limin@bxbb.com", "age",99) -- 进行封装
    -> );
Query OK, 1 row affected (0.00 sec)

mysql> select * from test_json;
+-----+------------------------------------------------------+
| uid | data                                                 |
+-----+------------------------------------------------------+
|   1 | {"age": 38, "name": "nazeebo", "address": "CD"}      |
|   2 | {"age": 37, "mail": "lowa@bxbb.com", "name": "lowa"} |
|   3 | {"age": 99, "name": "lm", "email": "limin@bxbb.com"} |
+-----+------------------------------------------------------+
3 rows in set (0.00 sec)

5.3 使用json_insert 插入数据

mysql> set @j = '{ "a": 1, "b": [2, 3]}';
Query OK, 0 rows affected (0.00 sec)

mysql> select json_insert(@j, '$.a', 10, '$.c', '[true, false]');
+----------------------------------------------------+
| json_insert(@j, '$.a', 10, '$.c', '[true, false]') |
+----------------------------------------------------+
| {"a": 1, "b": [2, 3], "c": "[true, false]"}        | //存在的不受影响,例如a还是=1
+----------------------------------------------------+ //c之前不存在,则插入
1 row in set (0.00 sec)

mysql>
mysql> select * from test_json;
+-----+------------------------------------------------------+
| uid | data                                                 |
+-----+------------------------------------------------------+
|   1 | {"age": 38, "name": "nazeebo", "address": "CD"}      |
|   2 | {"age": 37, "mail": "lowa@bxbb.com", "name": "lowa"} |
|   3 | {"age": 99, "name": "lm", "email": "limin@bxbb.com"} |
+-----+------------------------------------------------------+
3 rows in set (0.01 sec)

//  插入 addres_2
mysql> update test_json set data = json_insert(data, "$.address_2", "BJ") where uid = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from test_json;
+-----+--------------------------------------------------------------------+
| uid | data                                                               |
+-----+--------------------------------------------------------------------+
|   1 | {"age": 38, "name": "nazeebo", "address": "CD", "address_2": "BJ"} |  //对比发现插入了 addres_2
|   2 | {"age": 37, "mail": "lowa@bxbb.com", "name": "lowa"}               |
|   3 | {"age": 99, "name": "lm", "email": "limin@bxbb.com"}               |
+-----+--------------------------------------------------------------------+
3 rows in set (0.00 sec)

5.4 使用json_merge 合并数据并返回

注意:原数据不受影响

mysql> select json_merge('{"name": "zxx"}', '{"id": 9527}');
+-----------------------------------------------+
| json_merge('{"name": "zxx"}', '{"id": 9527}') |
+-----------------------------------------------+
| {"id": 9527, "name": "zxx"}                   |
+-----------------------------------------------+
1 row in set, 1 warning (0.00 sec)

mysql> select
    -> json_merge(
    -> json_extract(data, '$.address'), -- json 1
    -> json_extract(data, '$.address_2')) -- jons 2
    -> from test_json where uid = 1;
+----------------------------------------------------------------------------------+
| json_merge(
json_extract(data, '$.address'),
json_extract(data, '$.address_2')) |
+----------------------------------------------------------------------------------+
| ["CD", "BJ"]                                                                     |
+----------------------------------------------------------------------------------+
1 row in set, 1 warning (0.00 sec)

mysql> show warnings;
+---------+------+-----------------------------------------------------------------------------------------------------------------------------+
| Level   | Code | Message                                                                                                   |
+---------+------+-----------------------------------------------------------------------------------------------------------------------------+
| Warning | 1287 | 'JSON_MERGE' is deprecated and will be removed in a future release. Please use JSON_MERGE_PRESERVE/JSON_MERGE_PATCH instead |
+---------+------+-----------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> select
    -> JSON_MERGE_PRESERVE(
    -> json_extract(data, '$.address'), -- json 1
    -> json_extract(data, '$.address_2')) -- jons 2
    -> from test_json where uid = 1;
+-------------------------------------------------------------------------------------------+
| JSON_MERGE_PRESERVE(
json_extract(data, '$.address'),
json_extract(data, '$.address_2')) |
+-------------------------------------------------------------------------------------------+
| ["CD", "BJ"]                                                                              |
+-------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql>

5.5 使用json_array_append 追加数据

mysql>  set @j = '["a", ["b", "c"], "d"]';
Query OK, 0 rows affected (0.00 sec)

mysql> select json_array_append(@j, '$[1]', 1);
+----------------------------------+
| json_array_append(@j, '$[1]', 1) |
+----------------------------------+
| ["a", ["b", "c", 1], "d"]        |  //下标为1的值,增加“1”
+----------------------------------+
1 row in set (0.00 sec)

mysql> update test_json set data = json_array_append(
    -> data,
    -> '$.address',
    -> json_extract(data, '$.address_2'))
    -> where uid = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from test_json;
+-----+----------------------------------------------------------------------------+
| uid | data                                                                       |
+-----+----------------------------------------------------------------------------+
|   1 | {"age": 38, "name": "nazeebo", "address": ["CD", "BJ"], "address_2": "BJ"} |  //将address2的值添加到了address中去
|   2 | {"age": 37, "mail": "lowa@bxbb.com", "name": "lowa"}                       |
|   3 | {"age": 99, "name": "lm", "email": "limin@bxbb.com"}                       |
+-----+----------------------------------------------------------------------------+
3 rows in set (0.00 sec)

5.6 使用json_remove 从json记录中删除数据

mysql> set @j = '["a", ["b", "c"], "d"]';
Query OK, 0 rows affected (0.00 sec)

mysql>  select json_remove(@j, '$[1]');
+-------------------------+
| json_remove(@j, '$[1]') |
+-------------------------+
| ["a", "d"]              |  //删除下标为1的key和value
+-------------------------+
1 row in set (0.00 sec)

mysql> update test_json set data = json_remove(data, "$.address_2") where uid = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from test_json;
+-----+---------------------------------------------------------+
| uid | data                                                    |
+-----+---------------------------------------------------------+
|   1 | {"age": 38, "name": "nazeebo", "address": ["CD", "BJ"]} |  // address_2 的字段删除了
|   2 | {"age": 37, "mail": "lowa@bxbb.com", "name": "lowa"}    |
|   3 | {"age": 99, "name": "lm", "email": "limin@bxbb.com"}    |
+-----+---------------------------------------------------------+
3 rows in set (0.00 sec)

6. json 字段创建索引

JSON 类型数据本身 无法直接 创建索引,需要将需要索引的 JSON数据 重新生成虚拟列(Virtual Columns) 之后,对该列进行索引

6.1 新建表的时候创建json索引

1.创建表,建表的语法中抽取data中的name, 生成新的一列,名字为gen_col
mysql> create table test_json_index(
    ->  data json,
    ->  gen_col varchar(10) generated always as (json_extract(data, '$.name')),
    ->  index idx (gen_col) -- 将gen_col 作为索引
    ->  );
Query OK, 0 rows affected (0.03 sec)

mysql> show create table test_json_index\G
*************************** 1. row ***************************
       Table: test_json_index
Create Table: CREATE TABLE `test_json_index` (
  `data` json DEFAULT NULL,
  `gen_col` varchar(10) GENERATED ALWAYS AS (json_extract(`data`,'$.name')) VIRTUAL,
  KEY `idx` (`gen_col`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

2.插入两条数据
mysql> insert into test_json_index(data) values ('{"name":"lowa", "age":38, "address":"CD"}');
Query OK, 1 row affected (0.01 sec)

mysql>  insert into test_json_index(data) values ('{"name":"nazeebo", "age":66, "address":"SZ"}');
Query OK, 1 row affected (0.00 sec)

mysql> select * from test_json_index;
+-------------------------------------------------+-----------+
| data                                            | gen_col   |
+-------------------------------------------------+-----------+
| {"age": 38, "name": "lowa", "address": "CD"}    | "lowa"    |
| {"age": 66, "name": "nazeebo", "address": "SZ"} | "nazeebo" |
+-------------------------------------------------+-----------+
2 rows in set (0.00 sec)

3.查询的时候发现找不到记录
mysql> select json_extract(data,"$.name") as username from test_json_index where gen_col="lowa";
Empty set (0.00 sec)

4.原因是因为存储的时候连“”也存储了的
mysql>  select hex('"');
+----------+
| hex('"') |
+----------+
| 22       |
+----------+
1 row in set (0.00 sec)

mysql> select hex(gen_col) from test_json_index;
+--------------------+
| hex(gen_col)       |
+--------------------+
| 226C6F776122       |
| 226E617A6565626F22 |
+--------------------+
2 rows in set (0.00 sec)

5.所以带上双引号再去查询就可以得到正确的结果集
mysql> select json_extract(data,"$.name") as username from test_json_index where gen_col='"lowa"';
+----------+
| username |
+----------+
| "lowa"   |
+----------+
1 row in set (0.00 sec)

6.查看执行计划,使用了index的
mysql> explain select json_extract(data,"$.name") as username from test_json_index where gen_col='"lowa"' \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: test_json_index
   partitions: NULL
         type: ref
possible_keys: idx
          key: idx
      key_len: 43
          ref: const
         rows: 1
     filtered: 100.00
        Extra: NULL
1 row in set, 1 warning (0.00 sec)

7.为了避免出现连双引号一起存储的情况,采用json_unquote函数进行去掉双引号创建新的表test_json_index_2
mysql> create table test_json_index_2 (
    -> data json,
    -> gen_col varchar(10) generated always as (
    -> json_unquote( -- 使用json_unquote函数进行去掉双引号
    -> json_extract(data, "$.name")
    -> )),
    -> key idx(gen_col)
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql> show create table test_json_index_2\G
*************************** 1. row ***************************
       Table: test_json_index_2
Create Table: CREATE TABLE `test_json_index_2` (
  `data` json DEFAULT NULL,
  `gen_col` varchar(10) GENERATED ALWAYS AS (json_unquote(json_extract(`data`,'$.name'))) VIRTUAL,
  KEY `idx` (`gen_col`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.01 sec)

8.再次插入两条记录
mysql> insert into test_json_index_2(data) values ('{"name":"lowa", "age":38, "address":"CD"}');
Query OK, 1 row affected (0.01 sec)

mysql> insert into test_json_index_2(data) values ('{"name":"nazeebo", "age":66, "address":"SZ"}');
Query OK, 1 row affected (0.00 sec)

9.再次查询,发现能正确的获取到结果集
mysql> select json_extract(data,"$.name") as username from test_json_index_2 where gen_col="lowa";
+----------+
| username |
+----------+
| "lowa"   |
+----------+
1 row in set (0.00 sec)

10.查询执行计划,发现也使用了index
mysql> explain select json_extract(data,"$.name") as username from test_json_index_2 where gen_col="lowa"\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: test_json_index_2
   partitions: NULL
         type: ref
possible_keys: idx
          key: idx
      key_len: 43
          ref: const
         rows: 1
     filtered: 100.00
        Extra: NULL
1 row in set, 1 warning (0.00 sec)

6.2 修改已存在的表创建JSON索引

1.拿之前创建好的表test_json来做实验
mysql> show create table test_json\G
*************************** 1. row ***************************
       Table: test_json
Create Table: CREATE TABLE `test_json` (
  `uid` int(11) NOT NULL AUTO_INCREMENT,
  `data` json DEFAULT NULL,
  PRIMARY KEY (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

mysql> select * from test_json;
+-----+---------------------------------------------------------+
| uid | data                                                    |
+-----+---------------------------------------------------------+
|   1 | {"age": 38, "name": "nazeebo", "address": ["CD", "BJ"]} |
|   2 | {"age": 37, "mail": "lowa@bxbb.com", "name": "lowa"}    |
|   3 | {"age": 99, "name": "lm", "email": "limin@bxbb.com"}    |
+-----+---------------------------------------------------------+
3 rows in set (0.00 sec)

2.创建虚拟列
**注意:virtual 关键字是不将该列的字段值存储,对应的是stored**
mysql> alter table test_json
    -> add user_name varchar(32)
    -> generated always as (json_extract(data,"$.name")) virtual;
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> select * from test_json;
+-----+---------------------------------------------------------+-----------+
| uid | data                                                    | user_name |
+-----+---------------------------------------------------------+-----------+
|   1 | {"age": 38, "name": "nazeebo", "address": ["CD", "BJ"]} | "nazeebo" |
|   2 | {"age": 37, "mail": "lowa@bxbb.com", "name": "lowa"}    | "lowa"    |
|   3 | {"age": 99, "name": "lm", "email": "limin@bxbb.com"}    | "lm"      |
+-----+---------------------------------------------------------+-----------+
3 rows in set (0.00 sec)

3.添加索引
mysql> alter table test_json add index idx(user_name);
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

4.查看执行计划
mysql> explain select * from test_json where user_name='"lowa"'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: test_json
   partitions: NULL
         type: ref
possible_keys: idx
          key: idx
      key_len: 131
          ref: const
         rows: 1
     filtered: 100.00
        Extra: NULL
1 row in set, 1 warning (0.00 sec)

mysql> show create table test_json\G
*************************** 1. row ***************************
       Table: test_json
Create Table: CREATE TABLE `test_json` (
  `uid` int(11) NOT NULL AUTO_INCREMENT,
  `data` json DEFAULT NULL,
  `user_name` varchar(32) GENERATED ALWAYS AS (json_extract(`data`,'$.name')) VIRTUAL,
  PRIMARY KEY (`uid`),
  KEY `idx` (`user_name`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

七、字符集相关

1. MySQL字符集包括:

字符集(character) --用于定义字符串的存储方式 校对规则(collation) --用于定义比较字符串的方式 常用的字符集:

  • utf8:最常用的字符集,占3个字节
  • utf8mb4:utf8的超级,占4个字节
  • gbk : 占2个字节,通用性没有utf8好
  • gb18030: 是最新的汉字编码字符集国家标准, 向下兼容 GBK 和 GB2312 标准,编码是一二四字节变长编码
mysql> show character set;
+----------+---------------------------------+---------------------+--------+
| Charset  | Description                     | Default collation   | Maxlen |
+----------+---------------------------------+---------------------+--------+
| big5     | Big5 Traditional Chinese        | big5_chinese_ci     |      2 |
| dec8     | DEC West European               | dec8_swedish_ci     |      1 |
| cp850    | DOS West European               | cp850_general_ci    |      1 |
| hp8      | HP West European                | hp8_english_ci      |      1 |
| koi8r    | KOI8-R Relcom Russian           | koi8r_general_ci    |      1 |
| latin1   | cp1252 West European            | latin1_swedish_ci   |      1 |
| latin2   | ISO 8859-2 Central European     | latin2_general_ci   |      1 |
| swe7     | 7bit Swedish                    | swe7_swedish_ci     |      1 |
| ascii    | US ASCII                        | ascii_general_ci    |      1 |
| ujis     | EUC-JP Japanese                 | ujis_japanese_ci    |      3 |
| sjis     | Shift-JIS Japanese              | sjis_japanese_ci    |      2 |
| hebrew   | ISO 8859-8 Hebrew               | hebrew_general_ci   |      1 |
| tis620   | TIS620 Thai                     | tis620_thai_ci      |      1 |
| euckr    | EUC-KR Korean                   | euckr_korean_ci     |      2 |
| koi8u    | KOI8-U Ukrainian                | koi8u_general_ci    |      1 |
| gb2312   | GB2312 Simplified Chinese       | gb2312_chinese_ci   |      2 |
| greek    | ISO 8859-7 Greek                | greek_general_ci    |      1 |
| cp1250   | Windows Central European        | cp1250_general_ci   |      1 |
| gbk      | GBK Simplified Chinese          | gbk_chinese_ci      |      2 |
| latin5   | ISO 8859-9 Turkish              | latin5_turkish_ci   |      1 |
| armscii8 | ARMSCII-8 Armenian              | armscii8_general_ci |      1 |
| utf8     | UTF-8 Unicode                   | utf8_general_ci     |      3 |
| ucs2     | UCS-2 Unicode                   | ucs2_general_ci     |      2 |
| cp866    | DOS Russian                     | cp866_general_ci    |      1 |
| keybcs2  | DOS Kamenicky Czech-Slovak      | keybcs2_general_ci  |      1 |
| macce    | Mac Central European            | macce_general_ci    |      1 |
| macroman | Mac West European               | macroman_general_ci |      1 |
| cp852    | DOS Central European            | cp852_general_ci    |      1 |
| latin7   | ISO 8859-13 Baltic              | latin7_general_ci   |      1 |
| utf8mb4  | UTF-8 Unicode                   | utf8mb4_general_ci  |      4 |
| cp1251   | Windows Cyrillic                | cp1251_general_ci   |      1 |
| utf16    | UTF-16 Unicode                  | utf16_general_ci    |      4 |
| utf16le  | UTF-16LE Unicode                | utf16le_general_ci  |      4 |
| cp1256   | Windows Arabic                  | cp1256_general_ci   |      1 |
| cp1257   | Windows Baltic                  | cp1257_general_ci   |      1 |
| utf32    | UTF-32 Unicode                  | utf32_general_ci    |      4 |
| binary   | Binary pseudo charset           | binary              |      1 |
| geostd8  | GEOSTD8 Georgian                | geostd8_general_ci  |      1 |
| cp932    | SJIS for Windows Japanese       | cp932_japanese_ci   |      2 |
| eucjpms  | UJIS for Windows Japanese       | eucjpms_japanese_ci |      3 |
| gb18030  | China National Standard GB18030 | gb18030_chinese_ci  |      4 |
+----------+---------------------------------+---------------------+--------+
41 rows in set (0.00 sec)

2. collation(排序规则)

collation的含义是指排序规则, ci(case insensitive) 结尾的排序集是不区分大小写的

mysql> select 'a' = 'A';
+-----------+
| 'a' = 'A' |
+-----------+
|         1 |
+-----------+
1 row in set (0.00 sec)

mysql> create table test_ci (a varchar(10), key(a));
Query OK, 0 rows affected (0.03 sec)

mysql> insert into test_ci values('a');
Query OK, 1 row affected (0.01 sec)

mysql> insert into test_ci values('A');
Query OK, 1 row affected (0.01 sec)

mysql> select * from test_ci where a = 'a';
+------+
| a    |
+------+
| a    |
| A    |
+------+
2 rows in set (0.00 sec)

是不是感觉很神奇!!!a=A 居然是TRUE! 解释一下为什么会出现以上的情况。 首先,查下默认的排序规则

mysql> show variables like '%coll%';
+----------------------+--------------------+
| Variable_name        | Value              |
+----------------------+--------------------+
| collation_connection | utf8_general_ci    |
| collation_database   | utf8mb4_general_ci |
| collation_server     | utf8mb4_general_ci |
+----------------------+--------------------+
3 rows in set (0.00 sec)

ci(case insensitive) 结尾的排序集是不区分大小写的,所以才有了以上的结果

 // 修改当前session的collate,a终于不等于A 了,但是表里面的数据还是 a=A
 mysql> set names utf8mb4 collate utf8mb4_bin;
Query OK, 0 rows affected (0.00 sec)

mysql> select 'a' = 'A';
+-----------+
| 'a' = 'A' |
+-----------+
|         0 |
+-----------+
1 row in set (0.00 sec)

mysql> select * from test_ci where a = 'a';
+------+
| a    |
+------+
| a    |
| A    |
+------+
2 rows in set (0.00 sec)

//修改了session的collate对表数据不起作用,因为表自身也有collate。
//尝试给表修改collate
mysql> alter table test_ci collate utf8mb4_bin;
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

//发现还是a=A,这是因为只修改collate,对已经存在的数据不起作用
mysql> select * from test_ci where a = 'a';
+------+
| a    |
+------+
| a    |
| A    |
+------+
2 rows in set (0.00 sec)

// 要使得已经存在的数据也修改新的collate,需要用convert命令进行转换
mysql> alter table test_ci convert to character set utf8mb4 collate utf8mb4_bin;
Query OK, 2 rows affected (0.07 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> select * from test_ci where a = 'a';
+------+
| a    |
+------+
| a    |
+------+
1 row in set (0.00 sec)

mysql>

//另外,如果没有数据,可以直接用下面的sql进行修改
mysql> alter table test_ci character set utf8mb4 collate utf8mb4_bin;
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

3. 乱码问题

字符集涉及的范围很广,像程序链接、数据库、服务器、表以及表中的字段、结果集,都会涉及到字符集。字符集最容易遇到的问题就是乱码。

 mysql> show variables like '%char%';
+--------------------------+----------------------------------------------------------------+
| Variable_name            | Value                                                          |
+--------------------------+----------------------------------------------------------------+
| character_set_client     | utf8                                                           |
| character_set_connection | utf8                                                           |
| character_set_database   | utf8mb4                                                        |
| character_set_filesystem | binary                                                         |
| character_set_results    | utf8                                                           |
| character_set_server     | utf8mb4                                                        |
| character_set_system     | utf8                                                           |
| character_sets_dir       | /usr/local/mysql-5.7.22-linux-glibc2.12-x86_64/share/charsets/ |
+--------------------------+----------------------------------------------------------------+
8 rows in set (0.00 sec)

如何解决乱码呢? 答案是:保证三者一致。 三者包括:连接终端的字符集、操作系统的字符集、MySQL数据库的字符集。 如果想要临时的修改数据库字符集,可以在数据库命令行执行set names xxx来实现。 三者统一都是UTF8,就不会出现中文乱码的情况了。

Copyright © suredandan 2018 all right reserved,powered by GitbookUpdateTime: 2020-04-09 16:35:45

results matching ""

    No results matching ""