我们通过这个例子来看看
[root@xuegod63~]# mysql-u root-p123456mysql>create database xuegod2;mysql>use xuegod2;mysql>create tableworker(idintnot null,namevarchar(8)not null,passvarchar(20)not null);mysql>insert into workervalues(1,'HA','123456');mysql>insert into workervalues(1,'LB',null);ERROR1048(23000):Column'pass'cannot be null #不能为 nullmysql>insert into workervalues(2,'HPC','');
注:NOT NULL 的字段是不能插入“NULL”的,只能插入“空值”。
我们可能有这些疑问
(1) (2)为什么 not null 的效率比 null 高 (3)判断字段不为空的时候,到底要 select * from table where column <> ‘’ 还是要
用 select * from table where column is not null 呢。
“空值” 和 “NULL”有什么不一样?
空值是不占用空间的
MySQL 中的 NULL 其实是占用空间的,下面是来自于 MySQL 官方的解释
“NULLcolumns require additional space in the row to record whether their values areNULL.For MyISAM tables,eachNULLcolumn takes one bit extra,rounded up to the nearest byte.”
#“空列需要行中的额外空间来记录其值是否为空。对于 MyISAM 表,每个 NULL 列需要一个额外
的位,四舍五入到最接近的字节。
比如:一个杯子,空值’'代表杯子是真空的,NULL 代表杯子中装满了空气,虽然杯子看起来都是空
的,但是里面是有空气的。
对于问题 2,为什么 not null 的效率比 null 高?
NULL 其实并不是空值,而是要占用空间,所以 mysql 在进行比较的时候,NULL 会参与字段比
较,所以对效率有一部分影响。
而且索引时不会存储 NULL 值的,所以如果索引的字段可以为 NULL,索引的效率会下降很多。
因为 MySQL 难以优化引用可空列查询,它会使索引、索引统计和值更加复杂。可空列需要更多的存
储空间,还需要 MySQL 内部进行特殊处理。可空列被索引后,每条记录都需要一个额外的字节,还能导
致 MyISAM 中固定大小的索引变成可变大小的索引--------这也是《高性能 MySQL 第二版》介绍的解
读:“可空列需要更多的存储空间”:需要一个额外字节作为判断是否为 NULL 的标志位“需要 MySQL 内
部进行特殊处理” 所以使用 not null 比 null 效率高
对于问题 3,判断字段不为空的时候,到底要 select * from table where column <> ‘’ 还是
要用 select * from table where column is not null 我们举例看看
mysql>create tabletest(col1varchar(10)not null,col2varchar(10)null)ENGINE=MyISAM;mysql>insert into testvalues('',null);mysql>insert into testvalues('1','2');mysql>insert into testvalues('','1');mysql>select*from test;
下面我分别用这两条语句查询看看
mysql>select*from test where col1 is not null;
mysql>select*from test where col1<>'';
为空表示不占空间,null 占用空间
为字段指定默认的值
mysql>create tabletest2(namevarchar(8)not null,deptvarchar(25)default'SOS');mysql>insert intotest2(name)values('kko');mysql>select*from test2;
总结:
如果字段没有设定 default ,MySQL 依据这个字段是 null 还是 not null,如果可以为 null,则为
null。如果不可以为 null,则报错。
如果时间字段,默认为当前时间 ,插入 0 时,默认为当前时间。
如果是 enum 类型,默认为第一个元素。
自动增长
只能修饰 int 字段。 表明 MySQL 应该自动为该字段生成一个唯一没有用过的数(每次在最大 ID
值的基础上加 1。
特例:如果目前最大 ID 是 34,然后删除 34,新添加的会是 35.)。
对于主键,这是非常 有用的。可以为每条记录创建一个惟一的标识符。
mysql>create tableitems(idintnot null auto_increment primary key,labelvarchar(20)not null);mysql>insert intoitems(label)values('aaba');mysql>insert into itemsvalues(9,'aaba');
插入一个比上面数字小的值,会是下面的结果
再插入一条 id 将为多少
mysql>insert intoitems(label)values('abc');mysql>select*from items;
Id 为10mysql>insert into itemsvalues(9,'adl');ERROR1062(23000):Duplicate entry'9'forkey'PRIMARY'insert intoitems(label)values('abcs');#IDmax=11max=11delete from items where label='abcs';#IDmax=10max=11insert intoitems(label)values('abcsw');#Idmax=11max=12
原因:主键约束唯一
清空表中所有记录
方法一:
delete 不加 where 条件,清空所有表记录。但是 delete 不会清零 auto_increment 值
mysql>delete from items;Query OK,5rowsaffected(0.00sec)mysql>insert intoitems(label)values("aaaa");
方法二:
删除表中所有记录,清 auto_increment 值。
truncate
作用: 删除表的所有记录,并清零 auto_increment 值。新插入的记录从 1 开始。
语法: truncate table name;mysql>truncate table items;Query OK,0rowsaffected(0.01sec)mysql>insert into itemsvalues(null,'abv');
mysql>insert intoitems(label)values('hkuyb');mysql>select*from items;
索引是一种特殊的文件(InnoDB 数据表上的索引是表空间的一个组成部分),它们包含着对数据表
里所有记录的引用指针。更通俗的说,数据库索引好比是一本书前面的目录,能加快数据库的查询速度。
优点:为了加快搜索速度,减少查询时间。
缺点:
索引是以文件存储的。如果索引过多,占磁盘空间较大。而且他影响: insert ,update ,delete
执行时间。
索引中数据必须与数据表数据同步:如果索引过多,当表中数据更新的时候后,索引也要同步更
新,这就降低了效率。
索引的类型:
普通索引
唯一性索引
主键索引(主索引)
复合索引
最基本的索引,不具备唯一性,就是加快查询速度
创建普通索引:
方法一:创建表时添加索引
create table 表名(
列定义
index 索引名称 (字段)
index 索引名称 (字段)
)
注:可以使用 key,也可以使用 index 。index 索引名称 (字段),索引名称,可以加也可以不
加,不加使用字段名作为索引名。
mysql>create tabledemo(idint(4),namevarchar(20),pwdvarchar(20),index(pwd));注意:index 和 key 是相同的mysql>create tabledemo1(idint(4),namevarchar(20),pwdvarchar(20),key(pwd));mysql>create tabledemo2(idint(4),namevarchar(20),pwdvarchar(20),keyindex_pwd(pwd));#加上名称
方法二: 当表创建完成后,使用 alter 为表添加索引
alter table 表名 add index 索引名称 (字段1,字段2.....);
查看索引
mysql>desc demo;
注:如果 Key 是 MUL, 就是一般性索引,该列的值可以重复, 该列是一个非唯一索引的前导列(第一
列)或者是一个唯一性索引的组成部分但是可以含有空值 NULL。就是表示是一个普通索引。
show create table xxx; 先查看建表时的索引名
我们先删除索引
mysql> alter table demo drop key pwd; #注意此处的 pwd 指的是索引的名称,而不是
表中 pwd 的那个字段
再用 alter 添加
mysql>alter table demo addkey(pwd);mysql>alter table demo add keyindex_name(name);#也可以加其他字段索引
与普通索引基本相同,但有一个区别:索引列的所有值都只能出现一次,即必须唯一,用来约束内
容,字段值只能出现一次,应该加唯一索引。唯一性允许有 NULL 值<允许为空>。
创建唯一索引:
方法一:创建表时,加唯一索引
create table 表名(列定义:unique key 索引名 (字段);)
注意:常用在值不能重复的字段上,比如说用户名,电话号码,身份证号。
mysql>create tabledemo3(idint(4)auto_increment primary key,uNamevarchar(20),uPwdvarchar(20),uniqueindex(uName));
方法二:修改表时,加唯一索引
alter table 表名 add unique 索引名(字段);mysql>alter table demo3 drop key uName;mysql>alter table demo3 addunique(uName);
查询数据库,按主键查询是最快的,每个表只能有一个主键列,可以有多个普通索引列。主键列要求
列的所有内容必须唯一,不允许为空
创建主键索引
方法一:创建表创建主键索引
mysql>create tabledemo5(idint(4)not null auto_increment,namevarchar(20)defaultnull,primarykey(id));mysql>desc demo5;
mysql>show create table demo5;mysql>show index from demo5 \G
方法二:创建表后添加<不推荐>如果生产的数据无法保证唯一,创建主键报错
再添加
先删除测试
删除遇到这种情况是 auto_increment 的原因
mysql>alter table demo5 change id idint(4)not null;#先取消自增长mysql>alter table demo5 drop primary key;再删除主键mysql>alter table demo5 change id idint(4)not null primary key auto_increment;
数据要符合主键约束才能成功
总结:主键索引,唯一性索引区别:主键索引不能有 NULL,唯一性索引可以有空值
用存储过程的方式插入 100 万数据并测试
create tabletest_1(idintnot null auto_increment primary key,datavarchar(100),datevarchar(30));delimiter// #分割符create procedureprod_dba()begin declare iint;set i=0;whilei<1000000doinsert intotest_1(data,date)values('100','2020-01-01');set i=i+1;endwhile;end;//callprod_dba();//Query OK,1rowaffected(1min47.94sec)delimiter;#使用完马上恢复默认的分割符select*from test_1 where id=100000;#用时0秒alter table test_1 change id idint(10)not null;alter table test_1 drop primary key;
有索引比没索引的查询时间快了 0 点几秒,如果更复杂的表结构查询时间会差更多。
索引可以包含一个、两个或更多个列。两个或更多个列上的索引被称作复合索引
例: 创建一个表存放服务器允许或拒绝的 IP 和 port,表记录中 IP 和 port 要唯一。
mysql>create tablefirewall(hostvarchar(15)not null,portsmallint(4)not null,accessenum('deny','allow')not null,primarykey(host,port));#联合主键mysql>desc firewall;
mysql>insert into firewallvalues('10.96.52.46',22,'deny');mysql>insert into firewallvalues('10.96.52.46',21,'allow');mysql>insert into firewallvalues('10.96.52.46',21,'allow');ERROR1062(23000):Duplicate entry'10.96.52.46-21'forkey'PRIMARY'
插入两个一样就报错,唯一
全文索引(也称全文检索)是目前搜索引擎使用的一种关键技术。它能够利用分词技术等多种算法智能分析出文本文字中关键字词的频率及重要性,然后按照一定的算法规则智能地筛选出我们想要的搜索结果。
MySQL 在数据量较大的情况下,高并发连接的情况下。
select 语句 where bName like'%网%'
使用% _ 通配符,不通过索引,直接全表扫描。
ABSUWU LIKE ‘%U_U’
数据库压力大。
MySQL 的解决方案:全文索引:3.2 开始支持全文索引。无法正确支持中文。
从 MySQL 5.7.6 开始 MySQL 内置了 ngram 全文检索插件,用来支持中文分
全文索引只能用在 varchar text
创建全文索引:
方法一:创建表时创建
create table 表名(列定义,fulltext key 索引名 (字段);)
方法二:修改表时添加
alter table 表名 add fulltext 索引名 (字段);ALTER TABLE `books` ADD FULLTEXT[索引名](`author`)
强烈注意:MySQL 自带的全文索引只能用于数据库引擎为 MyISAM 的数据表,如果是其他数据引
擎,则全文索引不会生效。
一般交给第三方软件进行全文索引。
索引并非越多越好
数据量不大的不需要建立索引
列中的值变化不多不需要建立索引 row id
经常排序(order by 字段)和分组(group by 字段)的列需要建立索引
select a.bTypeId,(select b.bTypeName from category b where a.bTypeId=b.bTypeId)bn,count(*)from books a group by bTypeId;
5.唯一性约束对应使用唯一性索引
table(id pri,use,name index,pass);
foreign key 就是表与表之间的某种约定的关系,由于这种关系的存在,我们能够让表与表之间的数据,更加的完整,关联性更强。
关于完整性,关联性我们举个例子
例:
有二张表,一张是用户表,一张是订单表
如果我删除了用户表里的用户,那么订单表里面与这个用户有关的数据,就成了无头数据了,不
完整了。
如果我在订单表里面,随便插入了一条数据,这个订单在用户表里面没有与之对应的用户。这样
数据也不完整了。
如果有外键的话,就方便多了,可以不让用户删除数据,或者删除用户的话,通过外键同样删除
订单表里面的数据,这样也能让数据完整。
外键: 每次插入或更新时,都会检查数据的完整性。
方法一:通过 create table 创建外键
语法:
create table 数据表名称(...,[CONSTRAINT[约束名称]]FOREIGN KEY[外键字段]REFERENCES[外键表名](外键字段,外键字段2…..)[ON DELETE CASCADE][ON UPDATE CASCADE])constraint[kənˈstreɪnt]限制references[ˈrefrənsɪz]涉及;关联cascade[kæˈskeɪd]级联
关于参数的解释:
RESTRICT: 拒绝对父表的删除或更新操作。
CASCADE: 从父表删除或更新且自动删除或更新子表中匹配的行。ON DELETE CASCADE 和 ON
UPDATE CASCADE 都可用
注意:on update cascade 是级联更新的意思,on delete cascade 是级联删除的意思,意思就是
说当你更新或删除主键表,那外键表也会跟随一起更新或删除。
精简化后的语法:
语法:foreign key 当前表的字段 references 外部表名 (关联的字段) ENGINE =innodb
注:创建成功,必须满足以下 4 个条件:
1、确保参照的表和字段存在。
2、组成外键的字段被索引。
3、必须使用 ENGINE 指定存储引擎为:innodb。
4、外键字段和关联字段,数据类型必须一致。
例子:我们创建一个数据库,包含用户信息表和订单表
mysql>create database market;mysql>use market;mysql>create table `user`(idint(11)not null auto_increment,namevarchar(50)not nulldefault'',sexint(1)not nulldefault'0',primarykey(id))ENGINE=innodb;#创建时,如果表名是 sql 关键字,使用时,需要使用反引号``mysql>create table `order`(o_idint(11)auto_increment,u_idint(11)default'0',usernamevarchar(50),moneyint(11),primarykey(o_id),index(u_id),foreign keyorder_f_key(u_id)referencesuser(id)on delete cascade on update cascade)ENGINE=innodb;
注:on delete cascade on update cascade 添加级联删除和更新。
确保参照的表 user 中 id 字段存在。 组成外键的字段 u_id 被索引。 必须使用 type 指定存储引擎为:innodb。
外键字段和关联字段,数据类型必须一致。
插入测试数据
mysql>insert intouser(name,sex)values('HA',1),('LB',2),('HPC',1);mysql>insert into `order`(u_id,username,money)values(1,'HA',234),(2,'LB',146),(3,'HPC',256);mysql>select*from `order`;
mysql>select id,name,sex,money,o_id from user,`order` where id=u_id;
测试级联删除:
mysql>delete from user where id=1;#删除 user 表中 id 为1的数据
再查看 order 表。
mysql>select*from `order`;
测试级联更新:
更新前数据状态
mysql>select*from `order`;
mysql>select*from user;
mysql>update user set id=6where id=2;mysql>select*from user;
测试数据完整性:
mysql>insert into `order`(u_id,username,money)values(5,'Find',346);
外键约束,order 表受 user 表的约束
在 order 里面插入一条数据 u_id 为 5 用户,在 user 表里面根本没有,所以插入不进去
mysql>insert into uservalues(5,'Find',1);mysql>insert into `order`(u_id,username,money)values(5,'Find',346);#这里 u_id 只能是5mysql>select*from `order`;
语法
alter table 数据表名称 drop foreign key 约束(外键)名称mysql>alter table `order` drop foreign key order1_ibfk_1;mysql>show create table `order`;
什么是视图:
视图就是一个存在于数据库中的虚拟表。
视图本身没有数据,只是通过执行相应的 select 语句完成获得相应的数据。
我们在怎样的场景使用它,为什么使用视图 :
如果某个查询结果出现的非常频繁,要经常拿这个查询结果来做子查询
视图能够简化用户的操作
视图机制用户可以将注意力集中在所关心的数据上。如果这些数据不是直接来自基本表,则可以通过
定义视图,使数据库看起来结构简单、清晰,并且可以简化用户的数据查询操作
视图是用户能以不同的角度看待同样的数据。
对于固定的一些基本表,我们可以给不同的用户建立不同的视图,这样不同的用户就可以看到自己需
要的信息了。
视图对重构数据库提供了一定程度的逻辑性。
比如原来的 A 表被分割成了 B 表和 C 表,我们仍然可以在 B 表和 C 表的基础上构建一个视图 A,而
使用该数据表的程序可以不变。
视图能够对机密数据提供安全保护
比如说,每门课的成绩都构成了一个基本表,但是对于每个同学只可以查看自己这门课的成绩,因此
可以为每个同学建立一个视图,隐藏其他同学的数据,只显示该同学自己的
适当的利用视图可以更加清晰的表达查询数据。
有时用现有的视图进行查询可以极大的减小查询语句的复杂程度。
语法:create view 视图名称(即虚拟的表名) as select 语句。
在 book 数据库创建视图
mysql>use book;mysql>create view bc as select b.bName,b.price,c.bTypeName from books as b left join category as c on b.bTypeId=c.bTypeId;
可以按照普通表去访问。另外视图表中的数据和原数据表中数据是同步的。
2. 查看视图创建信息
mysql>show create view bc \G
3.查询视图中的数据
mysql>select*from bc where price<50\G
语法:
alter view 视图名称(即虚拟的表名) as select 语句。update view 视图名称(即虚拟的表名)set mysql>alter view bc as select b.bName,b.publishing,c.bTypeId from books as b left join category as c on b.bTypeId=c.bTypeId;mysql>select*from bc\G
查看有哪些可能视图
show table status where comment='view'\G
drop view 视图名。
mysql>drop view bc;
更多技术干货尽在公众号 “学神来啦” 持续为大家更新前沿技术和技术干货