MySQL基础下篇[表的创建/约束的使用/事务和范式以及索引的使用]~

创建表:

建表的语法格式:(建表属于DDL语句,DDL包括: create, drop, alter)

方式1:

create table 表名(字段名1 数据类型,字段名2,数据类型,字段名3,数据类型);

表名:建议以t_或者tbl_开始,可读性强,顾名思义

字段名:顾名思义

表名和字段名都属于标识符

数据类型:

其实在MySQL中包含了很多数据类型,但是我们只需要掌握一些常见的即可

char(最长255): 定长字符串

在这里插入图片描述

在上述实例中,我们规定名字的字段为10个字符,但是现在传入的Jack只有4个字符,由于char是定长字符长,因此即使传入的对象的字段小于10个,他依然会开辟10个内存空间大小,剩下未被占据的空间,将有空格补充

varchar(最长255): 可变长度的字符串

举例:

在这里插入图片描述

上述实例中,我们规定名字的字段为10个字符,但是现在传入的实例对象“jack”只有4个字符,那么此时varchar就会动态的分配4个字符的内存空间

对比于char,varchar的优点在于它比较智能,能够根据实际的数据长度动态分配空间,在一定程度上节省了空间,而char不论实际的数据长度是多少,都会分配定义时的固定长度去存储数据,使用不恰当的时候,可能会导致空间的浪费

既然如此,char就没有一丁点的好处吗?

当然不是,varchar虽然有那么多的优点,但是它有一个很大的缺点就是需要动态分配空间,速度慢,而char因为不需要动态分配内存空间,所以速度会比较快一些

那么他们二者该如何选择呢?

根据实际字段灵活变通

举例:

性别只包含两种:男or女,那么我们对于性别字段当然是选char,大可不必选择varchar

再比如名字字段,我们就必须选择varchar,因为它的长度并不是固定不变的

int(最长11):数字中的整数型,等价于Java中的int
bigint:数字中的长整形,等价于Java中的long
float:单精度浮点型数据
double:双精度浮点型
date:短日期类型
datetime:长日期类型
clob:字符串大对象

最多可以存储4G的字符串,比如:存储一篇文章,存储一个说明,超过255个字符的都需要使用该对象存储

blob:二进制大对象

专门用来存储照片声音,视频等流媒体数据

往blob类型的字段上插入数据的时候,例如插入一个图片,视频等,必须使用IO流才能完成

举例;

create table student1
(
id int,
name varchar(10),
age int(3),
sex char(1),
email varchar(255)
);

执行该命令后左边刷新:

在这里插入图片描述

删除表:

-- 建议采用第二种方式删除表

-- 第一种:
drop table t_student;-- 当这张表不存的时候会报错
-- 第二种
drop table if exists t_student ;-- 如果这张表存在,删除

插入数据:

语法格式:

-- 字段名和值需要一一对应,数量和数据类型都要相互对应
insert into 表名(字段名1,字段名2,字段名3......values(值1,值2,值3);

举例:

-- 完整插入
insert into student1 (id,name,age,sex,email) 
values(21100,'张三',10,'男','3242841279@qq.com');

查询结果:

在这里插入图片描述

-- 部分插入
insert into student1 (id) values(21100);

查询结果:

在这里插入图片描述

上述的部分插入,将数据成功插入了指定的字段id中,那么我们是否可以用同样的方法,将名字也插入呢?

insert into student1 (name) values('jack');

查询结果如下:

在这里插入图片描述

名字并没有成功插入我们上一条记录中的名字字段中,而是产生了一条新的记录

由此我们可以得出一个结论,insert语句但凡是执行成功了,那么必然会多一条记录,没有给其他字段指定字段值的话,默认值是NULL

修改默认值NULL:

修改某个字段的默认值:default

举例:

email varchar(255) default "无"

查询结果:

在这里插入图片描述

省略insert后面的字段名:

如果要省略字段名进行数据的插入,那么必须将数据与字段对应起来,比如第一个字段是id,那么你传输的第一个数据就必须需是id的值,顺序是不能颠倒的

insert into student2 values(2,"张三",18,'男',"75986@qq.com");

不能传入单个字段的数据,例如下述所举例的这种就是不可以的

insert into student2 values(2);

insert插入日期:

MySQL给出了一种函数:str_to_data()函数:

不过需要注意的是,该函数并不是专门的日期插入函数,而是将字符串转换为日期格式

语法格式:

str_to_date('字符串日期''日期格式')

MySQL的日期格式:

%y---年
%m---月
%d---日
%h---时
%i---分
%s---秒

举例:

insert into t_user(id,name,birth)values(21100234,张三,str_to_date('12-1900-1','%m-%Y-%d'));

但并不是所有的日期在插入的时候需要使用该函数进行转换,当你所插入的日期恰好满足%m-%Y-%d时,此时该字符串会被自动转换成日期类型

举例:

insert into t_user(id,name,birth)values(21100234,'张三','1999-12-1');

以默认格式显示日期:

举例:

select id,name,birth as birth from t_user;

查询结果:

在这里插入图片描述

以特定格式显示日期:

使用date_format()函数

举例:

select id,name,date_format(birth,'%m/%d/%y') as birth from t_user;

查询结果:

在这里插入图片描述

date和datetime的区别:

date是短日期:只包括年月日信息

MySQL默认短日期格式:%y-%m-%d

datetime是长日期:包括年月日时分秒信息

MySQL默认长日期格式:%y-%m-%d %h:%i:%s

获取系统当前时间:

now()函数

在定义时,应设置为datetime类型的,这样才能够精准的获取当前系统时间

修改表中的数据:update[DML]

语法格式:

update 表名 set 字段名1=1,字段名2=2,字段名3=3......where 条件;

注意:没有条件限制会导致所有数据全部更新

举例:

- 将id号为10的学生的姓名改变为"jason",年龄改变为10岁,生日改变为2000-10-10
update student set name='jason',age=10,birth='2000-10-10' where id=10;

注意:日期的格式在输入时,必须按照MySQL默认的格式来写

删除数据:delete[DML]

语法格式:

delete from 表名 where 条件;

注意:如果没有条件限制,整张表的数据会全部被删除

举例:

-- 删除student表中id为2的这条记录
delete from student from id=2;

-- 删除student表中的所有数据
delete from student;

上述这种删除数据的方式:执行效率比较慢,表中的数据被删除了,但是这个数据在硬盘上的真实存储空间不会被释放,因此它支持回滚,可以通过rollback;命令恢复已被删除的数据;

truncate语句:[DDL]

删除数据的效率比较高,表被一次截断,数据在硬盘上的真实存储空间也会得到释放,但是它并不支持回滚,数据一旦被删除就无法恢复

语法:

truncate table 表名;

上述所说的delete和truncate,都是删除表中的数据,而表结构并没有被删除,而下述的这种方法才是将表结构都给删除了

drop table 表名;	//删除表,将表中的数据连同表结构一起删除

插入数据:insert[DML]

语法格式:

插入单条数据:
insert  into 表名(字段1,字段2,字段3....values(1,值2,值3......);
插入多条数据:

语法格式:

insert into 表名(字段1,字段2,字段3....) values (1,值2,值3......),(1,值2,值3......),(1,值2,值3......).....;

快速创建表:

语法格式:

-- 将as后的查询结果当做要创建的新表
create table 表名 as select.....;

这可以完成表的快速复制,表在创建的瞬间,表中的数据也存在了

将查询结果插入到一张表当中:

-- 将select语句的查询结果插入到student表中
insert into student select......;

约束:

在创建表的时候,,我们可以给表中的字段增加一些约束,来保证这个表中数据完整性,有效性

非空约束:not null

举例:

当我们在创建表的时候,对于名字字段增加了约束条件不能为空,因此,当给该表插入数据时,名字部分的数据不能是空的

注:该约束只有列级约束,并没有表级约束

create table teacher(
	id int,
	name varchar(255) not null
);

小tip:xxxx.sql这种文件被称为sql脚本文件

sql脚本文件中编写了大量的sql语句,当我们执行sql脚本文件时,该文件中所有的sql语句都会被执行,如果想要批量的执行sql脚本文件,那么在MySQL中可通过source D:\course\03-Mysql\document\xxx.sql命令

唯一性约束:unique

唯一性约束的字段不能重复,但是可以为null

举例:

当我们在创建表的时候,对于id字段增加了约束条件不能为空,因此,当给该表插入数据时,id字段的数据不能重复

create table person(
	id int unique,
	age int,
);

两个字段联合起来具有唯一性:

假设我们要求表中的name和email联合起来具有唯一性:

错误写法:

create table t_vip(
	id int,
	name varchar(255) unique,	-- 约束添加到某个字段后面的约束属于列级约束
	name varchar(255) unique,
);

上述这种创建表是不符合我们的需求的,因为这样创建出来的表的含义是:email具有唯一性,name具有唯一性

那么对于下面将要插入表中的两组数据来说,并不能成功插入,原因是名字字段重复了

但是我们的需求是email+name联合具有唯一性即可,也就是说下面的两组数据,虽然名字字段重复,但是email字段并不重复,所以它们联合起来也是不重复的,理论上应该是可以插入数据的,因此上述这种创建表的方式是错误的

insert into t_vip(id,name,email) values(1,'张三','zhangsan@123.com');
insert into t_vip(id,name,email) values(1,'张三','zhangsan@sina.com');

正确写法:

create table t_vip(
	id int,
	name varchar(255),
	name varchar(255),
	unique(name,email),	//这种没有添加到某个列级后面的约束属于表级约束
);

此时才表示email+name唯一

当多个字段联合起来需要添加约束时,适用表级约束,单个字段需要添加约束,适用列级约束

not null和unique联合使用:

举例:

create table t_vip(
	id int,
	name varchar(255) not null unique	-- 表示name字段既不能为空,也不能重复
);

我们查看t_vip表结构,发现name字段变成了主键

在这里插入图片描述

在MySQL中,如果一个字段同时被not null和unique约束的话,该字段自动变成主键字段(注:在Oracle中并非如此)

主键约束:primary key(简称PK)

主键值是每一行记录的唯一标识,相当于人类的“身份证号”

在这里插入图片描述

任何一张表都应该有主键,没有主键的表是无效的

主键的特征:not null+unique[主键值不能是null,同时也不能重复]

单一主键

给表添加主键约束:

使用列级添加主键约束:

在这里插入图片描述

使用表级添加主键约束:

在这里插入图片描述

复合主键

在这里插入图片描述

在实际开发中,不建议使用复合主键,因为本身主键存在的意义就是作为某条记录的唯一标识,单一主键能够达到该效果

列级主键约束只能添加一个:

主键值的类型建议使用:int,bigint,char等类型,不建议使用:varchar来做主键,主键值一般都是数字,是定长的

对于主键的类型,除了我们上文提到的单一主键和复合主键之外,我们还可以将主键分为自然主键和业务主键。

自然主键:主键值是一个自然数,和业务没有关系

业务主键:主键值和业务密切相关,例如:拿银行卡账号做主键

在实际开发中,自然主键使用的会比较多一些,因为主键只要做到不重复就行,不需要有意义,业务主键不太好,因为主键一旦和业务挂钩,那么当业务发生变动时,可能会影响主键的值,所以业务主键不是我们所推荐的

主键自增机制:

在这里插入图片描述

外键约束:foreign key(简称FK)

业务背景:请设计数据库表,来描述"班级和学生"的信息

第一种方案:班级和学生存储在一张表中

在这里插入图片描述

这种存储数据的缺点是:数据冗余,空间浪费

第二种方案:班级一张表,学生一张表

在这里插入图片描述

当t_student表中的cno字段没有任何约束的时候,可能会导致数据无效,会出现除了t_class表中,当前存在的100/101以外的其他数字,所以为了保证cno字段中的值都是100和101,需要给cno字段添加外键约束,那么cno字段就是外键字段,cno字段中的每一个值都是外键值。

t_class是父表,t_student是子表:

删除表的顺序:先删子表,再删父表

若先删除父表,那么子表将会受到影响,因为它参照了父表中的很多数据

创建表的顺序:先创建父表,再创建子表

父表中的某些数据是子表建立的基础,因此,需要先建立父表

删除数据的顺序:先删除子表,再删除父表

如果先删除父表,那么子表将会不完整,因为它还在使用父表的数据

插入数据的顺序:先插入父表,再插入子表

子表需要使用父表的数据,因此没有父表,子表中的数据就是不完整的

举例:

在这里插入图片描述
子表中的外键引用的父表中的某个字段,被引用的这个字段不要求必须是主键,但是必须具有唯一性

子表中的外键是可以为空的

检查约束:check(MySQL不支持,Oracle支持)

存储引擎的使用:

存储引擎是MySQL中特有的一个术语,其他数据库中没有(Oracle中有,但是并不叫存储引擎),它实际上是一个表存储/组织数据的方式,不同的存储引擎,表存储数据的方式不同

数据库中的各表均被[在创建表时]指定的存储引擎来处理,服务器可用的引擎依赖于以下因素:

MySQL的版本
服务器在开发时如何被配置
启动选项

为了解当前服务器中有哪些存储引擎可用,可使用show engines命令

在这里插入图片描述

在建表时,指定引擎:

使用show create table 表名命令,可查看该表的结构数据:

在这里插入图片描述

MySQL默认的存储引擎是:InnoDB
MySQL默认的字符编码方式是:utf8

在建表时,设置存储引擎和字符编码方式:

在这里插入图片描述

查看当前MySQL支持的引擎有哪些:

在这里插入图片描述在这里插入图片描述

查看当前的MySQL版本:

在这里插入图片描述

MyISAM存储引擎是MySQL最常用的引擎

它管理的表具有以下特征:

使用三个文件表示每个表:
	格式文件-存储表结构的定义(mytable.fm)
	数据文件-存储表行的内容(mytable.MYD)
	索引文件-存储表上索引(mytable.MYI):相当于目录 ---缩小扫描范围,提升查询效率
灵活的AUTO_INCREMENT字段处理
MyISAM存储引擎的存储优势:可被转换为压缩,只读表来节省空间
MyISAM存储引擎的存储劣势:不支持事务,安全性较低

InnoDB存储引擎:

这是MySQL默认的存储引擎, InnoDB支持事务,支持数据库崩溃后自动恢复机制非常安全是它最大的一个特点

它管理的表具有下列主要特征:

 每个 InnoDB表在数据库目录中以.frm格式文件表示
 
 InnoDB表空间tablespace被用于存储表的内容(表空间是一个逻辑名称,表空间存储数据+索引)
 
 提供一组用来记录事务性活动的日志文件
 
 用commit(提交)savepointrollback(回滚)支持事务处理
 
 提供全acid兼容
 
 在MySQL服务器崩溃后提供自动恢复
 
 多版本(MVCC)和行级锁定
 
 支持外键及引用的完整性,包括联级删除和更新

InnoDB最大的特点就是支持事务:以保证数据的安全,效率不是很高,并且也不能压缩,不能转换为只读,不能很好地节省存储空间

MEMORY存储引擎:

使用MEMORY存储引擎的表,其数据存储在内存中,且行的长度固定,这两个特点使得MEMORY存储引擎非常快

MEMORY存储引擎管理的表具有以下特征:

在数据库目录内,每个表均以.frm格式的文件表示
表数据及索引被存储在内存中
表级锁机制
不能包含TEXTBLOB字段

MEMORY存储引擎之前被称为HEAP引擎

MEMORY存储引擎优点查询效率是最高的

MEMORY存储引擎缺点不安全,关机之后数据消失,因为数据和索引都是在内存当中

引入事务:

一个事务其实就是一个完整的业务逻辑,它是一个最小的工作单元,是不可再分的。

那么什么是一个完整的业务逻辑呢?

拿现实生活中的银行业务举例,假设转账,从A账户向B账户中转账10000,将A账户的钱减去10000(update语句),将B账户的钱加10000(update语句),这两步操作结合即为一个完整的业务逻辑。

以上的操作是一个最小的工作单元,要么同时成功,要么同时失败,不可再分

只有DML语句[insert,delete,update]才会有事务,其他语句和事务无关

事务机制

当业务只需要一条DML语句就能完成,那么事务就没有存在的价值了,因为正是做某件事时,需要多条DML语句结合才能够完成,才需要事务的存在,事务本质就是多条DML语句同时执行,或者同时失败

事务机制的执行过程:

InnoDB存储引擎:提供一组用来记录事务性活动的日志文件

事务开启:

insert
insert
insert
delete
update
update

事务结束!

在事务的执行过程中,每一条DML的操作都会记录到“事务性活动的日志文件”中,在事务的执行过程中,我们可以提交事务,也可以回滚事务

提交事务:

清空事务性活动的日志文件,将数据全部彻底持久化到数据库表中,提交事务标志事务的结束,并且是一种全部成功的结束

回滚事务:

将之前所有的DML操作全部撤销,并且清空事务性活动的日志文件,回滚事务标志着事务的结束,并且是一种全部失败的结束

自动提交机制:

提交事务:commit;
回滚事务:rollback;[回滚永远都是只能回滚到上一次的提交点]

经过如下测试:

在这里插入图片描述

我们得出,MySQL默认情况下是自动提交事务的,即为每执行一条DML语句,则提交一次

这种自动提交实际上是不符合我们的开发习惯,因为每一个业务通常是需要多条DML语句共同执行才能完成的,为了保证数据的安全,必须要求同时成功之后再提交所以不能执行一条就提交一条

关闭自动提交机制:

执行下述语句;

start transaction;

在这里插入图片描述

人为提交事务:

在这里插入图片描述

事务的4个特性:

A:原子性

说明事务是最小的工作单元,不可再分

C:一致性

所有事务要求,在同一个事务当中,所有操作必须同时成功,或者同时失败,以保证数据的一致性

I:隔离性

A事务和B事务具有一定的隔离

教室A和教室B之间有一道墙,所谓个隔离性就是指这道墙,A事务在操作一张表的时候,另一个事务B也操作这张表,相当于多线程并发访问同一张表

而A教室和B教室之间所隔的墙,可以很厚,也可以很薄,这就是事务的隔离级别,这道墙越厚,表示隔离级别越高

事务和事务之间的隔离级别有哪些?

读未提交:

read uncommitted(最低的隔离级别),事务A可以读取到事务B未提交的数据,这种隔离级别存在的问题就是:脏读现象(Dirty Read),即为读到了脏数据,这种隔离级别一般都是理论上的,大多数的数据库隔离级别第二档起步

验证
查看当前MySQL使用的隔离级别:

8.0以下版本使用该命令:

select @@tx_isolation

在这里插入图片描述

设置隔离级别为read uncommitted

执行下述命令:

set global transaction isolation level read uncommitted;

再次查询:

在这里插入图片描述

验证过程如下:

在这里插入图片描述

读已提交:

read committed,事务A只能读取到事务B提交之后的数据,这种隔离级别避免了读取到脏数据现象但是这种隔离级别不可重复读取数据,也就是说,在事务开启之后,第一次读到的数据是3条,当前事务还没有结束,可能第二次再读取的时候,读到的数据是4条,3不等于4,称为不可重复读取

这种隔离级别是比较真实的数据,每一次读到的数据是绝对真实的,Oracle数据库默认的隔离级别是:read committed

设置隔离级别为read committed

执行下述命令:

set global transaction isolation level read committed;

再次查询:

在这里插入图片描述

验证过程如下:

在这里插入图片描述

可重复读:

repeatable read,事务A开启之后,不管是多久,每一次在事务A中读取到的数据都是一致的,即使事务B将数据已经修改,并且提交了,事务A读取到的数据还是没有发生改变,这就是可重复读,它解决了不可重复读取数据的问题,但是它存在会出现幻影读的问题,即为每一次读取到的数据都是幻象,不够真实

设置隔离级别为repeatable read

执行下述命令:

set global transaction isolation level repeatable read;

再次查询:

在这里插入图片描述

验证过程如下:

在这里插入图片描述

举例:

早晨9点开启了事务,只要事务不结束,到晚上9点,读取到的数据还是那样,读到的都是假象。不够绝对的真实

MySQL中默认的事务隔离级别即为它

序列化/串行化:

serializable(最高的隔离级别),这是最高隔离级别,效率最低,解决了所有的问题,这种隔离级别表示事务排队,不能并发,synchronized,线程同步(事务同步),每一次读取到的数据都是最真实的,并且效率是最低的`

设置隔离级别为serializable

执行下述命令:

set global transaction isolation level serializable;

再次查询
在这里插入图片描述

验证过程如下:

在这里插入图片描述
D:持久性

事务最终结束的一个保障 —> 事务提交,就相当于将没有保存到硬盘上的数据保存到硬盘上

数据库设计范式:

第一范式:

要求任何一张表必须有主键,每一个字段原子性不可再分,第一范式是最核心,最重要的范式,所有的表的设计都需要满足

举例:

在这里插入图片描述

第二范式:

建立在第一范式的基础上,要求所有非主键字段完全依赖主键

在这里插入图片描述

以上的表并不满足第一范式

修改之后:

在这里插入图片描述

学生编号和教师编号两个字段联合做主键,复合主键(PK:学生编号+教师编号),经过修改之后,以上的表满足了第一范式,但是并不满足第二范式,因为"张三依赖1001”,“王老师依赖001”,显然产生了部分依赖,那么产生部分依赖有什么缺点呢?

数据冗余,空间浪费了,“张三”重复了,"王老师"重复了。

为了让上面这张表满足第二范式,我们对其进行修改

使用三张表来表示多对多的关系:

在这里插入图片描述

多对多设计技巧多对多,三张表,关系表两个外键

第三范式:

建立在第二范式的基础上,要求所有非主键字段直接依赖主键,不要产生传递依赖

在这里插入图片描述

以上表的设计是描述,班级和学生的关系,很显然是一对多的关系,一个教室中有多个学生。

以上表满足第一范式,因为它包含主键,且也满足第二范式,因为主键不是复合主键,没有产生部分依赖,主键是单一主键,但是并不满足第三范式,因为一年一班依赖01,01依赖1001,产生了传递依赖,不符合第三范式的要求,产生了数据的冗余。

修改如下:

在这里插入图片描述

一对多,两张表,多的表加外键

设计数据库表的时候,按照以上的范式进行,可以避免表中数据的冗余,空间的浪费。

数据库设计总结:

一对多,两张表,多的表加外键

多对多,三张表,关系表两个外键

一对一:在实际的开发中,可能存在一张表字段太多,太庞大,这个时候需要拆分

举例:

未拆分的一张表:

在这里插入图片描述

拆分成两张之后:

在这里插入图片描述

在这里插入图片描述

一对一,外键唯一

数据库设计三范式是理论上的,实践和理论有的时候有偏差,最终的目的都是为了满足客户的需求,有的时候会拿冗余换执行速度,因为在sql当中,表和表之间连接次数越多,效率越低(笛卡尔积),有的时候可能会存在冗余,但是为了减少表的连接次数,这样做也是合理的,并且对于开发人员来说,sql语句的编写难度也会降低

引入索引:

索引是在数据库表的字段上添加的是为了提高查询效率存在的一种机制一张表的一个字段可以添加一个索引,当然,多个字段联合起来也可以添加索引,索引相当于一本书的目录,是为了缩小范围而存在的一种机制

比如:对于一本字典来说,查找某个汉字有两种方式:

第一种方式:一页一页挨着查找,直到找到为止,这种查找方式属于全字典查找,效率比较低

第二种方式:先通过目录(索引)去定位一个大概的位置,然后直接定位到这个位置,做局域性扫描,缩小扫描的范围,快速的查找,这种查找方式属于通过索引检索,效率比较高。

举例:

select * from person where name='jack';

如果执行上述这条SQL语句,那么将会在name字段进行扫描,因为查询条件是:name=‘jack’;

如果name字段上没有添加索引[目录],或者说没有给name字段创建索引,MySQL会进行全扫描,会将name字段上的每一个值都对比一遍,效率比较低。

在这里插入图片描述

MySQL在查询方面主要就是两种方式:

第一种方式:全表扫描

第二种方式:根据索引检索

注意:

在实际开发中,汉语字典前面的目录是排序的,按照a b c d e f…排序,原因是只有排序了才会有区间查找这一说(缩小扫描范围其实就是扫描某个区间罢了),在MySQL数据库当中索引也是需要排序的,并且这个索引的排序和TreeSet数据结构相同,TreeSet(TreeMap)底层是一个自平衡的二叉树,在MySQL当中索引是一个B-Tree数据结构

遵循左小右大原则存放,采用中序遍历方式遍历存取数据

索引的实现原理:

假设有一张用户表:t_user

在这里插入图片描述

a:在任何数据库当中主键上都会自动添加索引对象,id字段上自动有索引,因为id是PK,另外在MySQL当中,一个字段上如果有unique约束的话,也会自动创建索引对象

b:在任何数据库当中,任何一张表的任何一条记录在硬盘存储上都有一个硬盘的物理存储编号

c:在MySQL当中,索引是一个单独的对象,不同的存储引擎以不同形式存在,在MyISAM存储引擎中,索引存储在一个.MYI文件中,在InnoDB存储引擎中索引存储在一个逻辑名称叫做tablespace的当中,在MEMORY存储引擎当中索引被存储在内存当中,不管索引存储在哪里,索引在MySQL当中都是一个树的形式存在

在这里插入图片描述

在MySQL当中,主键上,以及unique字段上都会自动添加索引,那么在什么条件下,我们会考虑给字段添加索引呢?

条件1:数据量非常庞大
条件2:该字段经常出现在where的后面,以条件的形式存在,也就是说这个字段总是被扫描
条件3:该字段很少的DML(insert delete update)操作,因为DML之后,索引需要重新排序

建议不要随意添加索引,因为索引也是需要维护的,太多的话反而会降低系统的性能,建议通过主键查询,建议通过unique约束的字段进行查询,效率都是比较高的

创建索引:

语法:

create index 索引名 on 表名(字段名);

举例:

//为person表中的id字段创建索引名为id_student_index
create index id_student_index on  person(id);

删除索引:

语法:

drop index 索引名 on 表名;

举例:

//删除person表上名为id_student_index的索引
drop index id_student_index on person;

使用SQL语句查询当前某个字段是否添加索引:

语法:

explain select ......where=“需要查看是否添加索引的字段名”;

在这里插入图片描述

索引失效:

第一种:当SQL语句的限制条件为模糊查询时,比如下述实例:

在这里插入图片描述

即使name字段上添加了索引,索引也不会生效,原因是因为模糊匹配当中以“%”开头,索引不知道从哪里开始查找,因此我们应该避免模糊查询的时候以“%”开始

第二种:使用or的时候会失效,比如下述实例:

在这里插入图片描述

使用or的时候会失效,如果使用or,那么要求or两边的条件字段都要有索引,那么索引才会生效,如果其中一边有一个字段没有索引,那么另一个字段上的索引也会失效

第三种:使用复合索引的时候,没有使用左侧的列查找,索引失效。比如下述实例:

复合索引即为:两个或两个以上字段联合起来添加一个索引

在这里插入图片描述

第四种:在where当中索引列参与了运算,索引失效。比如下述实例:

在这里插入图片描述

第五种:在where当中使用了函数,索引失效。比如下述实例:

在这里插入图片描述

索引的分类:

索引是各种数据库进行优化的重要手段,优化的时候优先考虑的因素就是索引,在数据库索引可以分为很多类:

单一索引:一个字段上添加索引
复合索引:两个字段或者更多的字段上添加索引
主键索引:主键上添加索引
唯一性索引:具有unique约束的字段上添加索引
..............

注:唯一性比较弱的字段上添加索引的用处不大

视图:

view:站在不同的角度去看待同一份数据,只有DQL语句才能以view的形式创建

创建视图:

create view 视图名 as  DQL语句[这里必须是DQL语句];

删除视图:

drop view 视图名;

视图的作用:

面向视图对象进行增删改查,对视图对象的增删改查会导致原表被操作(视图的特点:通过对视图的操作,会影响原表数据)

举例:

在这里插入图片描述

假设有一条非常复杂的SQL语句,而这条SQL语句需要在不同的位置上反复使用,每一次使用这个SQL语句的时候都需要重新编写,非常的麻烦,那么我们可以将这条复杂的SQL语句以视图对象的形式新建,在需要编写这条SQL语句的位置直接使用视图对象,可以大大简化开发,并且有利于后期的维护,因为修改的时候只需要修改视图对象所映射的SQL语句,我们以后面向视图开发的时候,使用视图的时候可以像使用table一样,可以对视图进行增删改查等操作视图不是在内存当中,视图对象也是存储在硬盘上的,不会消失

注:视图对应的语句只能是DQL语句,但是视图对象创建完成之后,可以对视图进行增删改查操作

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

从未止步..

谢谢你的打赏,我会继续努力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值