mysql 详解02

参考朱双印的mysql 专题 http://www.zsythink.net/archives/category/%e5%ad%98%e5%82%a8/mysql/page/5/

本博客仅为笔者个人参考学习使用,推荐通过学习朱双印的mysql专题来全面学习

本篇包含的内容

  • 约束管理、索引管理、键管理语句
  • 视图管理语句

(一)约束管理、索引管理、键管理语句

关系型数据库中的数据约束的概念为:数据约束可以理解为向数据表中插入数据时要遵守的限制规则

mysql中的常用约束有主键约束、唯一键约束、外键约束、非空约束等,我们先列出其概念。

  • 主键:primary key,表上一个或多个字段的组合,填入主键字段中的数据,必须不同于已经存在的其它行的相同字段上的数据,而且也不能为空;一个表只能存一个主键,一个主键可以由多个字段组成
  • 惟一键:unique key,表上一个或多个字段的组合,填入其中字段中的数据,必须不同于已经存在的其它行的相同字段上的数据,但可以为空;一个表可以有多个唯一键;
  • 外键:foreign key,一个表中的外键字段中所能够插入的数据取值范围,取决于引用的另一个表上主键字段上的已经存在数据集合;

非空约束

添加非空约束,设置非空字段。使用如下语句为testtb表中的name字段添加非空约束。

alter table testtb modify name varchar(100) not null;

删除非空约束,去除非空约束只要将字段修改为可以为空即可,当然,如果字段有其他约束,不要忘了加载语句的后面。

alter table testtb modify name varchar(100null;

自动增长

添加自动增长,为字段设置自动增长,同样既可以使用change,也可以使用modify

如下语句表示为testtb表的id字段设置自动增长。

alter table testtb modify id int auto_increment;

如下语句表示为testtb表的id字段设置自动增长。

alter table testtb change id id int auto_increment;

删除自动增长,去除自动增长的语句可以结合着添加自动增长的语句查看。同样有两种方法,使用change或者modify均可。

alter table testtb change id id int;
alter table testtb modify id int;

使用change 可以修改字段的名称

主键约束

添加主键约束

使用如下两条语句中的任意一条均可为表设置主键,注意,一个表中只能有一个主键。

如下命令表示将testtb4中的id字段指定为表的主键,通过如下语句设置的主键的主键名称默认为PRIMARY。

alter table testtb4 add primary key(id);
alter table testtb4 add constraint primary key(id);

删除主键约束

去除主键时需要注意,不能直接删除主键,需要先删除自动增长,然后再删除主键。

注意:如果对应的主键上存在自动增长,则不能直接删除主键,需先删除自动增长后,再使用如下语句删除主键。同理,如果当前表的主键已经被其他表中的字段当做外键,那么则需要先删除其他表中的主外键关系,才能删除当前主键。

alter table testtb drop primary key;

唯一键约束

添加唯一键约束

使用如下语句,添加唯一键约束,唯一键的名称默认为字段名称,如果对一个字段重复创建唯一键,唯一键名称将会按照创建时的序号依次向后增加,但是针对同一个字段重复创建唯一键是没有任何意义的,也强烈不建议这样做。

alter table testtb add unique key(uid);

使用如下语句在创建唯一键的时候,可以指定唯一键的名称,例如,指定唯一键的名称为uni_test。

alter table testtb add unique key uni_test(test);

删除唯一键约束

使用如下语句删除唯一键uni_test,注意,删除唯一键时使用的是index关键字

alter table testtb drop index uni_test;

查看约束

desc test1

查看主外键对应关系

如下语句表示查看test1这张表中引用了哪些表中的主键作为自己的外键。也可以理解为查看test1表的外键。

select TABLE_NAME,COLUMN_NAME,CONSTRAINT_NAME,REFERENCED_TABLE_NAME,REFERENCED_COLUMN_NAME from information_schema.KEY_COLUMN_USAGE where TABLE_NAME='test01' and REFERENCED_TABLE_NAME is not null;

如下语句表示查看test2这张表的主键被哪些表引用成为了外键,可以与上一个示例对比查看。

select REFERENCED_TABLE_NAME,REFERENCED_COLUMN_NAME,CONSTRAINT_NAME,TABLE_NAME,COLUMN_NAME from information_schema.KEY_COLUMN_USAGE where REFERENCED_TABLE_NAME='test2';

添加外键约束

使用如下两条语句设置外键,如下语句表示在testtb表中创建一个新的字段,tid,并且添加了一个外键,外键的名称叫testtb_tid_fk,外键中, testtb表中的tid字段引用了表testtb2表中的id字段

alter table testtb add column tid int default 0 not null;
alter table testtb add constraint testtb_tid_fk foreign key(tid) references testtb2(id);

删除外键约束

删除外键约束之前需要先查看外键约束的名称

select TABLE_NAME,COLUMN_NAME,CONSTRAINT_NAME,REFERENCED_TABLE_NAME,REFERENCED_COLUMN_NAME from information_schema.KEY_COLUMN_USAGE where TABLE_NAME = 'md_blogs' and REFERENCED_TABLE_NAME is not null;

使用如下语句 ,表示删除test4表中的 test_tid_fk 外键。

alter table test4 drop foreign key test_tid_fk;

索引管理

添加一个索引/创建一个纯粹的索引

这里所说的纯粹的索引指的就是index,不是unique index,只是单纯的index,使用如下语句表示为testtb表的name字段添加一个单纯的索引,索引的名字为ind_name

alter table testtb add index ind_name(name);

当我们使用上述语句添加索引以后,使用show index from testtb;可以查看到对应的索引,但是在information_schema.KEY_COLUMN_USAGE 表中将不会存在同名的"约束",而当我们创建一个唯一键或者唯一索引的时候,不仅能在information_schema.KEY_COLUMN_USAGE表中看到对应名称的"约束",同时还能使用show index from testtb;查看到对应名称的索引,这就体现了"键/约束"与"索引"的不同,当我们创建一个约束的时候,会创建对应的索引,但是如果只是创建一个单纯的索引,"纯index",那么它则只是一个"索引"罢了。

另外一种语法创建索引,语法如下。

CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name [using index_type] ON tbl_name (index_col_name,...)

上述语法中,我们可以指定创建哪种特殊索引,也可以只使用index,表示创建一个纯索引,[using index_type]表示索引类型,可省略,省略后默认使用btree类型的索引,并且指明在哪个表的哪个字段上创建索引。index_col_name用于指明字段名称,示例如下,如下语句表示在testtb表的name字段上创建一个索引,索引的名称为ind_name,索引的长度为20(注意,20并不是表示name字段的长度,假如name字段长度为100,此处指定20表示取出name字段的左边开头的头20个字节作为索引),索引为降序排列,不指定desc时默认以升序排序。

create index ind_name on testtb (name(20) desc);
create index ind_name on testtb (name(20));
create index ind_name on testtb (name);

如下示例语句表示创建一个联合索引

create index ind_id_name on testtb1 (id,name);
create index ind_id_name on testtb1 (id,name(20));

重建索引

数据库长时间运行后,索引会有损坏的可能,这个时候,重建索引,可以提高数据的检索速度,所以,重建索引的操作在平常的维护工作中可能会被用到,不过mariadb中的innodb存储引擎不支持重建索引。

repair table table_name quick;

删除一个索引

使用如下语句可以删除testtb表中的纯索引以及唯一索引。

alter table test2 drop index uu_ttt;

查看索引

查看testtb表中的所有索引

show index from testtb;

根据索引名称,查看testtb表中的部分索引,如下语句表示查看testtb表中以ind开头的索引。

show index from testtb where key_name like 'ind%';

(二)视图管理语句

视图的概念

视图是一个"虚表",用大白话说,就是从已经存在的表的全部字段或数据中,挑选出来一部分字段或数据,组成另一张"并不存在的表",这张虚表被称之"视图",视图中的字段与对应的数据均来自已经存在的表,对于视图来说,这些已经存在的表就被称为"基表",基表可以是一张表,也可以是多张表, 视图的本质可以理解为一条查询语句,视图中显示的结果,就是这条查询语句查询出的结果。

使用视图的理由

这个时候我们可能会有一个问题,既然视图中的字段均来自"基表",为什么还要使用"视图",我们直接使用"基表"就行了,干嘛还要用视图,这是有原因的,我们可以从以下几个方面理解。

1,简化操作

我们说过,视图中的数据可能来自于多张基表,如果基表有很多,而且基表之间存在复杂的关系,当我们需要找出某些数据时,可能需要执行一条复杂的sql语句,如果我们把这个复杂的sql语句创建为视图,我们就可以直接从视图的结果中使用简单的sql语句查询出需要的结果,这使我们容易理解和使用。

2,安全原因

安全原因往往是使用视图的主要原因,我们能通过视图,限制用户能够查看到的数据,比如我们创建了一张"供货商信息表",这张表里面存放了公司20个大区所有供货商的数据,如果我授权了数据库用户A对这张表有查看权限,那么A用户将有权利查看"供货商信息表"中所有供货商的信息,如果想要限制A用户,让其只能查看前三个大区的供货商信息,我们就可以使用视图,将前三个大区中的供货商信息查询出来,将对应sql语句创建成"前三大区供货商视图",然后授权A用户只能查看"前三大区供货商视图",但是不能查看"供货商信息表",那么数据库用户A则只能查看到前三个大区供货商的信息了,而不是能够看到所有供货商的信息,这就是我们之前所说的,视图是一张虚表,它的字段或者数据可能只是其他表中的一部分。

不使用视图的理由

mysql对于视图的优化并不完善,这样说并不准确,准确的说,应该是mysql对于子查询的优化不是很好,而使用视图本身往往就意味着使用子查询,所以,如果我们必须使用视图时,最好将视图中的sql语句尽量优化,或者说,数据量大的时候尽量避免使用视图。

创建视图

在创建视图之前,请先确定当前登录的数据库用户是否拥有创建视图的权限。

 查询结果中,create_view_priv的值为Y,表示当前用户拥有创建视图的权利。

我们来创建一个最简单的视图

我们可以把上图中创建视图的语句分成两个部分来看。

create view testvi as 当做第一部分,这部分语句实现的功能就是创建一个名叫testvi的视图,这个视图中的内容从as 后面的查询语句中获得。

select * from classes where classid <= 3;为上图中语句的第二部分,这部分语句的功能就是从classes表中查询出了classid号小于等于3的数据。

这两个部分结合在一起,就表示,我们将查询语句查询出的结果创建为一个名叫testvi的视图。

注意,视图是一种"虚表",所以不能与已经存在的表重名。

此处我们先查询出classes表中的所有内容,方便与视图中的内容做对比。

视图创建完了,我们来查看一下视图中的内容,视图是一种"虚表",我们查看视图就像查看表一样即可。

 可以看到,即使我们查询出了testvi视图中的所有信息,也只有3条数据,这3条数据都来自于classes表,还记得我们在概念中提到的"安全原因"吗,这种场景就跟"安全原因"中提到的场景相同。

我们也可以使用如下语句创建视图

create or replace view testvi as select * from classes where classid <= 4;

create or replace view testvi as 表示,如果testvi这个视图如果不存在,那么则按照指定的查询语句创建视图,如果当下已经存在testvi这个视图,那么则使用当前视图覆盖之前的testvi视图,以当前的sql查询语句作为视图的语句。

我们发现,视图创建后,视图中的字段名与"基表"中的字段名称相同,我们也可以让视图使用自己的字段名,而不是使用基表中的字段名称,我们可以在创建视图时使用如下语句。

 我们在概念中提到过,视图是由其他表中的一部分数据或者字段组成的,我们也可以只查询出"基表"中的部分字段,组成视图,示例如下

从上述的举例中我们可以看出,创建视图是很简单的,视图中的内容主要取决于我们的查询sql写成什么样。

所以,我们也可以通过sql语句,从多个表中查询出数据,创建视图。

 其实在创建视图时,还可以指定mysql处理视图的算法,算法会影响MySQL处理视图的方式,mysql可以使用两种算法处理视图,这两种算法为MERGE算法和TEMPTABLE算法,我们可以在创建视图时,使用ALGORITHM指定使用哪种算法处理当前视图,ALGORITHM的值可以设置为MERGE、TEMPTABLE、UNDEFINED。如果没有ALGORITHM子句,默认值为UNDEFINED(表示用户未指定固定的算法,mysql会自动从MERGE、TEMPTABLE中选择一个算法处理视图),那么这些算法有什么不同呢,我们后面再解释,先看看创建时的示例语句。

上述语句表示指定使用merge算法处理视图。

那么,每种算法有什么不同呢。

1、MERGE算法:视图使用这种算法时,如果我们调用了视图,mysql会先将视图的定义转换成sql语句,然后把视图的sql语句与我们调用的语句整合,最后执行整合完毕的sql语句,什么意思呢,就以上图中的创建视图的sql语句为例,如果我们想要查看视图testvi中的所有数据,我们有可能会执行select * from testvi这条sql语句 ,如果testvi使用的是merge算法,那么mysql会先将执行的语句变成 select * from (select name,age from students;) ,然后执行最终改变过的语句,这就是merge算法对视图的处理过程,如果使用这种算法,即使定义视图时的sql语句不包含子查询,在我们调用视图的时候,最终执行的sql语句本身就一定包含子查询,而mysql对子查询的优化是不够的,当数据量大时,往往会影响性能,这就是不使用视图的理由。

2、TEMPTABLE算法:视图的结果将被置于临时表中,然后使用它执行语句,什么意思呢,还是以上图中的testvi视图为例,如果把上图中的merge改成temptable,当我们执行 select * from testvi时,mysql会先查询到会先将select name,age from students;的查询结果放置到临时表中,然后用户的语句再调用临时表中的数据,当视图使用这种算法时,视图只能用于查询,不能用于更新数据

3、UNDEFINED:当algorithm设置为此值时,MySQL将选择所要使用的算法。如果可能,它倾向于MERGE而不是TEMPTABLE,这是因为MERGE通常更有效,而且如果使用了临时表,视图是不可更新的

 删除视图

删除视图很简单,使用如下语句删除testvi视图

drop view testvi;

如下语句表示如果视图testvi存在,则删除;

drop view if exists testvi;

查看视图

我们可以查看数据库中存在哪些视图,也可以查看视图的结构,还可以查看视图中的内容,我们一个一个来。

首先,如果我们想要查看某一数据库中的所有视图,可以使用如下语句查看:

select * from information_schema.views where table_schema='U_DB_NAME';

示例如下:

 我们也可以查看视图的结构,就像查看表的结构一样;

 我们也可以查看视图中的数据内容,就像查看表一样

 修改视图

修改视图的语句如下

 更新视图中的数据

在大部分情况下,创建视图是为了查看数据的,很少会去更新视图中的数据,即使想要去更新视图中的数据,也需要满足一定的条件,不是所有视图中的的数据都是可更新的。

如果视图包含下述结构中的情况,那么它将是不可更新的:

· 当视图设定了 ALGORITHM = TEMPTABLE。

· 聚合函数(SUM(), MIN(), MAX(), COUNT()等)。

· 位于选择列表中的子查询。

· FROM子句中存在不可更新视图。

· WHERE子句中的子查询,引用FROM子句中的表。

· 仅引用文字值(此时没有要更新的基表)。

· 基表中的其他字段中的约束不被满足。

· DISTINCT

· GROUP BY

· HAVING

· UNION 或 UNION ALL

· Join

注意:视图中虽然可以更新数据,但是有很多的限制。所以,一般我们只在查询时使用视图,而不要通过视图更新数据。

原文地址:https://www.cnblogs.com/faberbeta/p/mysql-02.html