MySQL 之存储引擎与数据类型与数据约束
一.存储引擎场景
1.InnoDB
用于事务处理应用程序,支持外键和行级锁。如果应用对事物的完整性有比较高的要求,在并发条件下要求数据的一致性,数据操作除了插入和查询之外,还包括很多更新和删除操作,那么InnoDB存储引擎是比较合适的。InnoDB除了有效的降低由删除和更新导致的锁定,还可以确保事务的完整提交和回滚,对于类似计费系统或者财务系统等对数据准确要求性比较高的系统都是合适的选择。
2.MyISAM
如果应用是以读操作和插入操作为主,只有很少的更新和删除操作,并且对事务的完整性、并发性要求不高,那么可以选择这个存储引擎。
3.Memory
将所有的数据保存在内存中,在需要快速定位记录和其他类似数据的环境下,可以提供极快的访问。Memory的缺陷是对表的大小有限制,虽然数据库因为异常终止的话数据可以正常恢复,但是一旦数据库关闭,存储在内存中的数据都会丢失。
#查看当前的默认存储引擎:
show variables like "default_storage_engine";
#更改表的存储引擎
alter table t1 engine = innodb;
方法2:
#my.ini文件
[mysqld]
default_storage_engine=INNODB
4.BLACKHOLE
# BLACKHOLE使用场景:
如图:用户访问网站时,先通过负载均衡系统
来进行用户的分发,底层会用一系列类似于取模的算法,给用户进行分配,目的让服务器所抗住的并发均衡;
有的用户需要查询,有的用户需要修改或者添加,但是整体查询次数会远远大于增删改的次数,
那么这时搭建主从数据库.主数据库负责写入,从数据库负责读取,
为了让主从数据库,数据同步,中间在加上一台服务器,用于同步,那么这台服务器所用的存储引擎就是blackhole
专门帮助主数据库进行binlog日志的生成和分发.从数据库拿到binlog日志后,开始同步自己的数据
这样的好处,主数据库只专注于写入,不用考虑分发其他数据等操作;减少服务器的压力;
中间blackhole的mysql服务器不需要生产或者消费数据,只是单纯的过滤生产binlog日志,所以选择blackhole存储引擎.
5.了解不同引擎创建数据库产生的文件结构
create table innodb1(id int , name char(4)) engine=innodb;
show create table innodb1;
innodb1.frm 表结构
innodb1.ibd 表数据
create table myisam1(id int ,name char(4)) engine=myisam;
myisam1.frm 表结构
myisam1.MYD 表数据
myisam1.MYI 表索引 从上到下,从左到右依次查询,如果设置该字段是索引,会单独拿出来一个文件进行存储查询,速度更快.
create table memory1(id int ,name char(4)) engine=memory;
memory1.frm 表结构
create table blackhole1(id int ,name char(4)) engine=blackhole;
blackhole1.frm 表结构
insert into blackhole1 values(1,"s");
在配置文件中指定默认的存储引擎:
/etc/my.cnf
[mysqld]
default-storage-engine=INNODB
innodb_file_per_table=1
二.数据类型
1.number类型(数字类型)
(1)整型
tinyint 1个字节 有符号(-128 ~ 127) 无符号(0~255) 小整数值
int 4个字节 有符号(约-21亿 ~ 21亿 最大长度10位) 无符号(0~42亿) 大整数值,精确度更高
create table t1(id int unsigned,sex tinyint);
insert into t1 values(4200000000,128); #22003): Out of range value for column 'sex' at row 1
insert into t1 values(4200000000,127);
(2)浮点型
float(255,30) 单精度
double(255,30) 双精度
decimal(65,30) 一般用于保存金钱,是使用字符串的形式来保存小数,
create table t2(f1 float(5,2) , f2 double(5,2),f3 decimal(5,2));
insert into t2 values(1.234,1.234,1.234);
# decimal 默认保留整数 double默认保留的小数位数更多,更精确.
create table t3(f1 float, f2 double,f3 decimal);
insert into t3 values(1.2355555555,1.2355555555,1.2355555555);
number类型详细见下列表格:
2.str类型(字符串类型)
char(11) 定长:固定开启字符长度是11的空间 (手机号,身份证号),速度快
varchar(11) 变长:最大开辟字符长度是11的空间 (文章评论 5~255个字数之间.),速度慢
text 这种类型应用在文章,小说中.
create table t4(c char(11),v varchar(11),t text);
insert into t4 values('1122',"dfdffd","34234234243");
select concat(c,v) from t4;
select concat(c,",",v) from t4;
详细见表格:
3.时间类型
date YYYY-MM-DD 年月日 (出生日期)
time HH:MM:SS 时分秒 (竞赛时间)
year YYYY 年分值 (红酒82年拉菲 82年矿泉水)
datetime YYYY-MM-DD HH:MM:SS 年月日时分秒 (登录时间,下单时间)
create table t5(d date ,t time ,y year ,dt datetime);
insert into t5 values(now(),now(),now(),now());
insert into t5 values("2020-1-1","23:23:23","2038","2099-1-1 23:23:23");
timestamp YYYYMMDDHHMMSS 自动更新时间戳,不需要你手动写入(修改表的时候,自动更新,到时候可以看到最后一次表更新时间;)
create table t6(dt datetime,ts timestamp);
insert into t6 values(null,null);
insert into t6 values(20190103121212,20190103121212);
insert into t6 values(20190103121212,20380118121212);
如果timestamp这个效果没有实现,需要将explicit_defaults_for_timestamp=true这句配置删除,重启服务,然后重新建一个数据库和数据表才能体现效果.
详细见表格:
4.枚举&集合
enum 和 set 的数据必须从其中挑选,没有的话报错;
enum 枚举 从一组数据中选一个 (一般性别上)
set 集合 从一组数据中选多个 ,自动去重
详细见表格:
例:
create table stu1( id int primary key auto_increment, name char(5), sex enum('male','female'), #enum 代表枚举类型 hobbies set('eat','play','study','coding') #set 代表集合类型 ); insert into stu1(name,sex,hobbies) values('haiyan','none','dsfdg'); # 这个报错 select * from stu1; #如果设置了sex是枚举类型,就的从设定的里面选其中的一个存 insert into stu1(name,sex,hobbies) values('yan','female','play,study'); # 这个 可以插入数据 select * from stu1; #如果设置了hobbies是集合类型,就得从设定的里面选其中一个或者多个值来存
三.数据约束
约束:对插入数据库的值进行限制,不满足条件的不让操作数据。
约束本质上是对数据在数据类型限定的基础上添加的额外的要求。
unsigned 无符号整型
not null: 不能为空,此字段不允许填写空值。
default : 设置默认值。当不填写字段对应的值会使用默认值,如果填写时以填写为准。
unique : 唯一约束,数据唯一,此字段的值不允许重复。
primary key: 主键,唯一不为空的值.可以唯一表达每条记录[辨别数据唯一性的一个身份证]
auto_increment: 自增加1,[一般是对unique或者 primary key 进行设置]
foreign key: 外键,把多张表通过一个字段关联在一起。对关系字段进行约束, 当为关系字段填写值时, 会到关联的表中查询此值是否存在, 如果存在则填写成功, 如果不存在则填写失败并抛出异常。
zerofill : 零填充,位数不够的时候用前导0
注意:
MySQL 建议所有表的主键字段都叫 id, 类型为 int unsigned。
虽然外键约束可以保证数据的有效性, 在进行数据的 crud(增删改查), 会降低数据库的性能, 此种情况下不推荐使用。
# not null: 不能为空
create table t7(id int not null,name varchar(255));
insert into t7 values(1,null);
# default : 设置默认值
create table t8(id int not null,name varchar(255) default "wangwen" );
# insert into t8 values(2,null);
# 特别指定id字段插入,另一个字段使用默认值;
insert into t8(id) values(3);
# unique : 唯一约束,数据唯一,不重复,unique 默认允许插入空值
create table t9(id int unique,name char(12) default 'lisi');
insert into t9(id) values(1);
# insert into t9(id) values(1); # error
insert into t9(id) values(null);
insert into t9(id) values(null);
# primary key: 主键,唯一不为空的值.可以唯一表达每条记录[辨别数据唯一性的一个身份证]
# 原型:create table t10(id int not null unique,name char(10) default '马军强');
# primary key 可以直接指定主键;
create table t11(id1 int not null unique,id2 int primary key );
desc t11;
create table t12(id int primary key,name varchar(20) default "张国成");
desc t12
insert into t12(id) values(1);
insert into t12(id) values(null);
# auto_increment: 自增加1,[一般是对unique或者 primary key 进行设置]
create table t13(id int primary key auto_increment , name varchar(10) default 'LIN');
insert into t13 values(5,"aabb");
insert into t13 values(null,'ccdd');
给一个字段设置非空唯一是主键 (常用,一个表里面只能有一个)
联合多个字段设置非空唯一是联合主键 (不常用,一个表里可以有多个)
如果两个类型的主键同时存在,默认会在单个字段上显示PRI
# 1 联合唯一约束 unique(字段1,字段2...) => .unique(ip,port)约束是一个相对泛泛的概念,可以是主键,索引,非空,默认值等等;
# (1)联合唯一主键:非空+联合唯一的约束 => 显示 PRI
create table t1_server(id int,server_name char(10) not null ,ip char(15) not null,port int not null,unique(ip,port))
insert into t1_server(id,server_name,ip,port) values(4,'aa',"192.168.16.3",3306);
insert into t1_server(id,server_name,ip,port) values(4,'aa',"192.168.16.3",3307);
insert into t1_server(id,server_name,ip,port) values(4,'aa',"192.168.16.3",3306);
# (2)显示索引 : 可空+联合唯一约束 => 显示MUL 普通索引
create table t2_server(id int,server_name char(10) not null ,ip char(15),port int,unique(ip,port))
# 在建立联合主键的时候,请务必把相应字段设置为非空,否则默认插入null 是允许的;
insert into t2_server(id,server_name,ip,port) values(4,'aa',null,null);
insert into t2_server(id,server_name,ip,port) values(5,'aa',null,null);
insert into t2_server(id,server_name,ip,port) values(6,'aa',"192.168.16.3",3306);
insert into t2_server(id,server_name,ip,port) values(7,'aa',"192.168.16.3",3306);
# (3)如果2中类型(主键和联合主键)都在一个表当中出现,如何显示?
alter table t1_server add primary key(id)
# 2.zerofill : 零填充,位数不够的时候用前导零填充
create table ceshi01(id int(5) zerofill);
insert into ceshi01 values(3);
# 3.foreign key: 外键,把多张表通过一个字段关联在一起
'''外键要求:所关联的字段必须唯一 (要么unique , 要么主键,用来连接2张表,一般为主键) '''
student1:
id name age classname
1 xiaowen 17 c5
2 ma qiang 98 c5
3 zhangcheng 97 c5
4 yitian 100 c5
5 zhangsan 45 c6
5 zhangs 35 c6
# 出现过多冗余的数据,开始分表,利用外键关联
student1:
id name age
1 xiaowen 18
2 maju 19
3 cheng 18
class1:
id classname
1 c5
2 c6
# 先创建class1 表
create table class1(id int,classname varchar(255));
# 设置id为unique
alter table class1 add unique(id);
# 创建学生表,创建外键(一般会把外键设置在一对多,多的那张表上面)
# foreign key(class_id) references class1(id)
create table student1(id int primary key auto_increment,name varchar(255),age int,class_id int,foreign key(class_id) references class1(id))
# 插入数据
insert into class1 values(1,"c5");
insert into class1 values(2,"c6");
insert into student1 values(null,"aa",13,1);
insert into student1 values(null,"aa",13,2);
# ->删除的是不带外键的那张表,会拒绝删除
# delete from class1 where id = 1
'''
on update cascade 联级更新
on delete cascade 联级删除
'''
create table class2(id int unique,classname varchar(255));
create table student2(id int primary key auto_increment,name varchar(255),age int,class_id int unique,foreign key(class_id) references class2(id) on update cascade on delete cascade);
insert into class2 values(1,"c5");
insert into class2 values(2,"c6");
insert into student2 values(null,"aa",13,1);
insert into student2 values(null,"aa",13,2);
# ->加了联级更新和删除之后 更新可以,删除慎用;2
# delete from class2 where id = 1 会把关联的所有数据删掉;
# 表与表之间的关系
(1)一对一 : 一个人对应一个身份证号 在外键上设置 unique foreign key 两张表的该字段身上都标注了unique
(2)一对多或者多对一 : 一个班级对应多个学生,[在多的那个表里创建外键,关联另外表的一个字段]
(3)多对多 :一个学生对应多个学科,一个学科可以对应多个学生 , 一本书可以对应多个作者,一个作者也可以写多本书
如果存在多对多的关系,要单独创建关系表,
xueke: (主表1)
id xueke_name
1 math
2 huaxue
3 english
4 wuli
student: (主表2)
id studentname
1 xiaowen
2 zhangcheng
3 mayan
relation:
xid sid
1 1
1 2
1 3
2 1
2 2
2 3