卧槽,你怎么知道的,Null多简单啊,不传值设置Null多方便啊,而且不占用什么空间,代码也不用填写,也不用判断了。
二狗,你知道你这样的随行所欲会发生哪些Bug么?下面就给你好好的说说Null会产生哪些情况
mysql> select length(''), length(null), length(0),length('0');
+------------+--------------+-----------+-------------+
| length('') | length(null) | length(0) | length('0') |
+------------+--------------+-----------+-------------+
| 0 | NULL | 1 | 1 |
+------------+--------------+-----------+-------------+
1 row in set (0.00 sec)
-- 不要使用 NULL 字段
CREATE TABLE `mysql_escape`.`do_not_use_null` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`one` varchar(10) NOT NULL,
`two` varchar(20) DEFAULT NULL,
`three` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_one` (`one`),
KEY `idx_two` (`two`),
UNIQUE KEY `idx_three` (`three`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 初始化一些数据
INSERT INTO `mysql_escape`.`do_not_use_null`(`id`, `one`, `two`, `three`) VALUES (1, '', 'a2', 'a3');
INSERT INTO `mysql_escape`.`do_not_use_null`(`id`, `one`, `two`, `three`) VALUES (2, 'b1', NULL, 'b3');
INSERT INTO `mysql_escape`.`do_not_use_null`(`id`, `one`, `two`, `three`) VALUES (3, 'c1', 'c2', NULL);
INSERT INTO `mysql_escape`.`do_not_use_null`(`id`, `one`, `two`, `three`) VALUES (4, 'c3', 'c4', NULL);
mysql> select * from do_not_use_null where two = null;
Empty set (0.00 sec)
mysql> select * from do_not_use_null where two is null;
+----+-----+------+-------+
| id | one | two | three |
+----+-----+------+-------+
| 2 | b1 | NULL | b3 |
+----+-----+------+-------+
1 row in set (0.00 sec)
由此得出结论 判断是否为null值只能使用is null或is not null语句
5.7 版本的mysql
mysql> desc select * from do_not_use_null where two != 'xxx'\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: do_not_use_null
partitions: NULL
type: ALL
possible_keys: idx_two
key: NULL
key_len: NULL
ref: NULL
rows: 3
filtered: 100.00
Extra: Using where
1 row in set, 1 warning (0.00 sec)
mysql> desc select * from do_not_use_null where two is not null\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: do_not_use_null
partitions: NULL
type: range
possible_keys: idx_two
key: idx_two
key_len: 63
ref: NULL
rows: 2
filtered: 100.00
Extra: Using index condition
1 row in set, 1 warning (0.00 sec)
上面两个从key(idx_two)可以看出来 只有是is null 的情况下 才可以使用索引
**8.0 对此做了优化 ** 只截取不等于的情况
mysql> desc select * from do_not_use_null where two != 'xxx'\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: do_not_use_null
partitions: NULL
type: range
possible_keys: idx_two
key: idx_two
key_len: 63
ref: NULL
rows: 3
filtered: 100.00
Extra: Using index condition
1 row in set, 1 warning (0.00 sec)
唯一性索引失效的场景,索然three 字段创建了唯一性索引,但是可以插入多条为null的情况,此时索引是失效的
null参与的任何计算返回的结果都是null
mysql> select 1+Null;
+--------+
| 1+Null |
+--------+
| NULL |
+--------+
1 row in set (0.00 sec)
mysql> select concat('abc', Null);
+---------------------+
| concat('abc', Null) |
+---------------------+
| NULL |
+---------------------+
1 row in set (0.00 sec)
对字段为null 的进行聚合是不会计算在内的
mysql> select count(*) from do_not_use_null;
+----------+
| count(*) |
+----------+
| 4 |
+----------+
1 row in set (0.00 sec)
mysql> select count(three) from do_not_use_null;
+--------------+
| count(three) |
+--------------+
| 2 |
+--------------+
1 row in set (0.00 sec)
正序的排在前面,逆序的排在后面,这个是mysql的一个约定
mysql> select * from do_not_use_null order by two asc;
+----+-----+------+-------+
| id | one | two | three |
+----+-----+------+-------+
| 2 | b1 | NULL | b3 |
| 1 | | a2 | a3 |
| 3 | c1 | c2 | NULL |
| 4 | c3 | c4 | NULL |
+----+-----+------+-------+
4 rows in set (0.00 sec)
mysql> select * from do_not_use_null order by two desc;
+----+-----+------+-------+
| id | one | two | three |
+----+-----+------+-------+
| 4 | c3 | c4 | NULL |
| 3 | c1 | c2 | NULL |
| 1 | | a2 | a3 |
| 2 | b1 | NULL | b3 |
+----+-----+------+-------+
4 rows in set (0.00 sec)
二狗 : 原来null有这个多条条框框啊,看样子以后要注意他的使用了
#dokcer pull 镜像名:版本号
docker pull mysql:5.7
# docker run -p 对外暴露的端口:mysql运行端口 --name 容器名称 -e MYSQL_ROOT_PASSWORD=mysql连接密码 -d 镜像名:版本号
# -p 对外暴露的端口:mysql运行端口
# --name 容器名称 //镜像首次启动时会自动创建容器,需要给容器命名
# -e MYSQL_ROOT_PASSWORD=mysql连接密码 //mysql镜像容器创建时必须设置连接密码,否则无法创建容器
# -d 后台运行
docker run -p 3315:3306 --name mysql5.7 \
-e MYSQL_ROOT_PASSWORD=asd123456 \
-d mysql:5.7
# docker logs --tail=行数 容器名称
docker logs --tail=100 mysql5.7
# 先进入容器
docker exec -it mysql5.7 bash
mysql -uroot -p
# 授权外网访问
GRANT ALL PRIVILEGES ON *.* TO 'test'@'%' IDENTIFIED BY 'test123' WITH GRANT OPTION;
这个肯定有啊,想对接第三方的,对接慢,又不能影响开发,基本都先考虑srting 类型的
mysql创建表的时候不指定主键,但是一定要指定一个主键
如果没有制定主键的情况下,就会以是否存在非空整形的唯一索引作为主键,如果在没有的情况下,InnoDB会自动添加隐式主键
主键不具有任何的业务含义,只是一个唯一的自增整数值
mysql中定义了四类数据类型,且有不同的取值范围
mysql> help char
Name: 'CHAR'
Description:
[NATIONAL] CHAR[(M)] [CHARACTER SET charset_name] [COLLATE
collation_name]
A fixed-length string that is always right-padded with spaces to the
specified length when stored. M represents the column length in
characters. The range of M is 0 to 255. If M is omitted, the length is
1.
*Note*:
Trailing spaces are removed when CHAR values are retrieved unless the
PAD_CHAR_TO_FULL_LENGTH SQL mode is enabled.
URL: https://dev.mysql.com/doc/refman/5.7/en/string-type-syntax.html
枚举类型的选择
枚举类型的值都是从“允许值列表”中选择,且这个列表是在创建表结构时定义好的
| 枚举值 | 索引 |
|---|---|
| NULL | NULL |
| 空字符串 | 0 |
| male | 1 |
| female | 2 |
数据验证
CREATE TABLE `mysql_escape`.`suitable_data_type` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL,
`gender` ENUM('male', 'female') NOT NULL,
`grade` ENUM('0', '1', '2') NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--插入一条正确的数据(枚举值都是自己定义的)
mysql> INSERT INTO `mysql_escape`.`suitable_data_type`(`id`, `name`, `gender`, `grade`) VALUES (1, 'qinyi', 'male', '1');
Query OK, 1 row affected (0.01 sec)
-- 插入一条错误的数据, 会执行失败
mysql> INSERT INTO `mysql_escape`.`suitable_data_type`(`id`, `name`, `gender`, `grade`) VALUES (2, 'qinyi', 'male', '9');
ERROR 1265 (01000): Data truncated for column 'grade' at row 1
--查看枚举值对应的索引
mysql> select name, gender + 0, grade from suitable_data_type;
+-------+------------+-------+
| name | gender + 0 | grade |
+-------+------------+-------+
| qinyi | 1 | 1 |
+-------+------------+-------+
枚举类型的特性/需要注意的事项
mysql> INSERT INTO `mysql_escape`.`suitable_data_type`(`id`, `name`, `gender`, `grade`) VALUES (3, 'qinyi', 'male', 2);
Query OK, 1 row affected (0.01 sec)
-- 此时将字面量的值翻译成了索引
mysql> select id,name,gender,grade from suitable_data_type;
+----+-------+--------+-------+
| id | name | gender | grade |
+----+-------+--------+-------+
| 1 | qinyi | male | 1 |
| 3 | qinyi | male | 1 |
+----+-------+--------+-------+
mysql> INSERT INTO `mysql_escape`.`suitable_data_type`(`id`, `name`, `gender`, `grade`) VALUES (4, 'qinyi', 'male', '2');
\Query OK, 1 row affected (0.00 sec)
-- '2' 为字符串,在允许值范围内
mysql> select id,name,gender,grade from suitable_data_type;
+----+-------+--------+-------+
| id | name | gender | grade |
+----+-------+--------+-------+
| 1 | qinyi | male | 1 |
| 3 | qinyi | male | 1 |
| 4 | qinyi | male | 2 |
+----+-------+--------+-------+
mysql> INSERT INTO `mysql_escape`.`suitable_data_type`(`id`, `name`, `gender`, `grade`) VALUES (5, 'qinyi', 'male', '3');
Query OK, 1 row affected (0.01 sec)
-- '3' 对应的索引值范围刚好是 2
mysql> select id,name,gender,grade from suitable_data_type;
+----+-------+--------+-------+
| id | name | gender | grade |
+----+-------+--------+-------+
| 1 | qinyi | male | 1 |
| 3 | qinyi | male | 1 |
| 4 | qinyi | male | 2 |
| 5 | qinyi | male | 2 |
+----+-------+--------+-------+
-- 不再允许范围内
mysql> INSERT INTO `mysql_escape`.`suitable_data_type`(`id`, `name`, `gender`, `grade`) VALUES (6, 'qinyi', 'male', '4');
ERROR 1265 (01000): Data truncated for column 'grade' at row 1
mysql> select sum(gender) from suitable_data_type;
+-------------+
| sum(gender) |
+-------------+
| 4 |
+-------------+
1 row in set (0.00 sec)
mysql> select avg(gender) from suitable_data_type;
+-------------+
| avg(gender) |
+-------------+
| 1 |
+-------------+
1 row in set (0.00 sec)
mysql> INSERT INTO `mysql_escape`.`suitable_data_type`(`id`, `name`, `gender`, `grade`) VALUES (7, 'abc', 'female', '0');
Query OK, 1 row affected (0.01 sec)
mysql> select * from suitable_data_type order by gender;
+----+-------+--------+-------+
| id | name | gender | grade |
+----+-------+--------+-------+
| 1 | qinyi | male | 1 |
| 3 | qinyi | male | 1 |
| 4 | qinyi | male | 2 |
| 5 | qinyi | male | 2 |
| 7 | abc | female | 0 |
+----+-------+--------+-------+
5 rows in set (0.00 sec)
-- 转换成字符
mysql> select * from suitable_data_type order by cast(gender as char);
+----+-------+--------+-------+
| id | name | gender | grade |
+----+-------+--------+-------+
| 7 | abc | female | 0 |
| 1 | qinyi | male | 1 |
| 3 | qinyi | male | 1 |
| 4 | qinyi | male | 2 |
| 5 | qinyi | male | 2 |
+----+-------+--------+-------+
5 rows in set (0.00 sec)
mysql> select * from suitable_data_type order by concat(gender);
+----+-------+--------+-------+
| id | name | gender | grade |
+----+-------+--------+-------+
| 7 | abc | female | 0 |
| 1 | qinyi | male | 1 |
| 3 | qinyi | male | 1 |
| 4 | qinyi | male | 2 |
| 5 | qinyi | male | 2 |
+----+-------+--------+-------+
这个么,看情况啊,具体的反正就是字段出现的频率啥的吧,其他还给老师了。
额,你丫的,这个不行啊,下面就和你好好说说索引的使用
验证
-- 第一类
CREATE TABLE `mysql_escape`.`correct_use_index` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL,
`age` int(11) NOT NULL,
`phone` varchar(64) NOT NULL,
`email` varchar(128) NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_phone` (`phone`),
KEY `idx_name_phone_email` (`name`, `phone`, `email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 查看表的索引
mysql> show index from correct_use_index \G;
*************************** 1. row ***************************
Table: correct_use_index
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: id
Collation: A
Cardinality: 0
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
*************************** 2. row ***************************
Table: correct_use_index
Non_unique: 1
Key_name: idx_phone
Seq_in_index: 1
Column_name: phone
Collation: A
Cardinality: 0
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
*************************** 3. row ***************************
Table: correct_use_index
Non_unique: 1
Key_name: idx_name_phone_email
Seq_in_index: 1
Column_name: name
Collation: A
Cardinality: 0
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
*************************** 4. row ***************************
Table: correct_use_index
Non_unique: 1
Key_name: idx_name_phone_email
Seq_in_index: 2
Column_name: phone
Collation: A
Cardinality: 0
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
*************************** 5. row ***************************
Table: correct_use_index
Non_unique: 1
Key_name: idx_name_phone_email
Seq_in_index: 3
Column_name: email
Collation: A
Cardinality: 0
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
-- 没有字符串没有使用索引
mysql> explain select * from correct_use_index where phone = 17012345678\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: correct_use_index
partitions: NULL
type: ALL
possible_keys: idx_phone
key: NULL
key_len: NULL
ref: NULL
rows: 1
filtered: 100.00
Extra: Using where
1 row in set, 3 warnings (0.00 sec)
-- 有字符串使用索引
mysql> explain select * from correct_use_index where phone = '17012345678'\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: correct_use_index
partitions: NULL
type: ref
possible_keys: idx_phone
key: idx_phone
key_len: 194
ref: const
rows: 1
filtered: 100.00
Extra: NULL
-- where 条件左边的字段参与了函数或者数学运算
mysql> explain select * from correct_use_index where concat(name, '-qinyi') = 'imooc-qinyi'\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: correct_use_index
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 1
filtered: 100.00
Extra: Using where
mysql> explain select * from correct_use_index where name = 'imooc'\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: correct_use_index
partitions: NULL
type: ref
possible_keys: idx_name_phone_email
key: idx_name_phone_email
key_len: 98
ref: const
rows: 1
filtered: 100.00
Extra: NULL
-- 联合索引的前缀使用问题(虽然优化器会重排 where 顺序, 但是, 查询条件最好还是按照定义的联合索引的顺序, 而不是每次顺序都不一样, 这样也会让查询缓存失效, 因为查询语句不一样了)
mysql> drop index idx_phone ON correct_use_index;
mysql> explain select * from correct_use_index where name = 'qinyi' and phone = '10086' and email = 'qinyi@imooc.com'\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: correct_use_index
partitions: NULL
type: ref
possible_keys: idx_name_phone_email
key: idx_name_phone_email
key_len: 678
ref: const,const,const
rows: 1
filtered: 100.00
Extra: NULL
mysql> explain select * from correct_use_index where phone = '10086' and email = 'qinyi@imooc.com'\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: correct_use_index
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 1
filtered: 100.00
Extra: Using where
数据准备
-- 第二类
CREATE TABLE `mysql_escape`.`correct_use_index_2` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`career` varchar(32) NOT NULL,
`first_name` varchar(16) NOT NULL,
`last_name` varchar(16) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `mysql_escape`.`correct_use_index_2`(`id`, `career`, `first_name`, `last_name`) VALUES (1, 'engineer', 'qinyi', 'abcdefg');
INSERT INTO `mysql_escape`.`correct_use_index_2`(`id`, `career`, `first_name`, `last_name`) VALUES (2, 'engineer', 'qinyi', 'abxyzbdf');
INSERT INTO `mysql_escape`.`correct_use_index_2`(`id`, `career`, `first_name`, `last_name`) VALUES (3, 'engineer', 'qinyi', 'aerefgdgfd');
INSERT INTO `mysql_escape`.`correct_use_index_2`(`id`, `career`, `first_name`, `last_name`) VALUES (4, 'engineer', 'qinyi', 'abpoijhyg');
INSERT INTO `mysql_escape`.`correct_use_index_2`(`id`, `career`, `first_name`, `last_name`) VALUES (5, 'engineer', 'qinyi', 'acqasdwqer');
验证
-- 索引选择性(没有必要为索引选择性较低的列创建索引)
mysql> select count(distinct(career))/count(*) from correct_use_index_2;
+----------------------------------+
| count(distinct(career))/count(*) |
+----------------------------------+
| 0.2000 |
+----------------------------------+
-- 想要通过 name 去查询记录, 可以考虑创建 first_name 索引, 或 first_name、last_name 联合索引 --> 看一看索引选择性
select * from correct_use_index_2 where first_name = '' and last_name = '';
-- 索引度比较低,选择联合索引,选区 last_name 部分字符组合
mysql> select count(distinct(first_name))/count(*) from correct_use_index_2;
+--------------------------------------+
| count(distinct(first_name))/count(*) |
+--------------------------------------+
| 0.2000 |
+--------------------------------------+
-- first_name, last_name 创建联合索引占据的空间会过大, 需要考虑兼顾长度和选择性
select count(distinct(concat(first_name, last_name)))/count(*) from correct_use_index_2;
select count(distinct(concat(first_name, left(last_name, 1))))/count(*) from correct_use_index_2;
select count(distinct(concat(first_name, left(last_name, 2))))/count(*) from correct_use_index_2;
mysql> select count(distinct(concat(first_name, left(last_name, 3))))/count(*) from correct_use_index_2;
+------------------------------------------------------------------+
| count(distinct(concat(first_name, left(last_name, 3))))/count(*) |
+------------------------------------------------------------------+
| 1.0000 |
+------------------------------------------------------------------+
ALTER TABLE correct_use_index_2 ADD INDEX `idx_first_last_name_3` (first_name, last_name(3));
show index from correct_use_index_2;
建议 :
这个我知道,有乐观锁对不对,乐观锁是通过类似版本号来的,悲观锁就是要等待执行完
按照锁数据的力度(等级) 分析
行级锁 表级锁
按照数据的锁定方式区分
乐观锁 悲观所 (排他锁 共享锁)
啊,这个,我都是用explain定位的
mysqldumpslow -s -t 10 -g “group by” /tmp/slow_query.log
参数说明
-s 按照何种方式排序 记录次数 c 时间 t 查询时间 l 返回记录数r
-t TOP N
-g 正则匹配模式,大小写不敏感
mysql> explain select * from correct_use_index where phone = '10086' and email = 'qinyi@imooc.com'\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE **查询中每个select子句的类型**
table: correct_use_index
partitions: NULL
type: ALL
possible_keys: NULL **可能使用的索引,索引中使用的字节数**
key: NULL
key_len: NULL
ref: NULL
rows: 1 **估算需要读取的数据行**
filtered: 100.00 **满足查询记录数的比例**
Extra: Using where
1 row in set, 1 warning (0.01 sec)