数据库中最基本的单元 --> 表 --> 表比较直观
\c 中止指令
mysql -uroot -p
exit;
mysql> create database ****;
mysql> show databases;
mysql> use ****;
mysql> show tables;
mysql> source 文件路径(如:D:\mysql\test.sql)
mysql> desc 表名
分为:
DQL(Data Query Language):
数据查询语言(凡是带有select关键字的都是查询语句) select...
DML(Data Mainipulation Language):
数据操作语言(凡是对表当中的数据进行增删改的都是DML) insert,delete,update
DDL(Data Definition Language):
数据表定义语言(主要操作表结构,不是表中的数据) 凡是带有create,drop,alter都是DDL
TCL(Transactional Control Langguage):
事务控制语言 事务提交->commit,事务回滚->rollback
DCL(Data Control Language):
数据控制语言 如:授权grant、撤销权限revoke
selsec * from 表名
selsec 字段名,字段名 from 表名 selsec "字面量" from 表名
select 字段名,字段名 as 别名 from 表名 select 字段名,字段名 别名 from 表名 //加空格 select 字段名,字段名 '别名' from 表名 //若别名中有空格可以使用,加''
select name,i*12 '计数' from table
select name1,name2,name3, .. from 表名 where 条件;
条件类型
不等于 --> != ,<>
select sal from tabl where sal != 300;
select sal from tabl where <> 300;
等于 --> =
select sal from tab where sal = 200;
介于两个值之间 --> between … and … --> 必需遵循左小右大
select sal from tab where sal between 100 and 200;
查询为空的值 --> is null,不为空 --> not is null, null不能使用null衡量
select name from tab where name is null;
select name from tab where name not is null;
并且 and
select sal,name from tab where sal > 10 and name = '张';
或者 or
select empo from tabl where empo = '焊工' or empo = ‘电工’;
包含 in ,不是区间,in里面是具体的值,相当于多个or
not in 不包含
select sal from tab where sal in (100,500,200);
select sal from tab where sal not in (100,500,200);
like 模糊查询,支持 %
和 _
匹配,%
匹配任意多个字符,_
任意一个字符,如:
------------------------- % 的使用------------------------------------ //找出名字 name 中包含 ma 的值 select name from tab where name like '%ma%'; //找出名字 name 以k 结尾的 select name from tab where name like 'k%'; //找出名字 name 以bg 开头的 select name from tab where name like '%bg'; ------------------------- _ 的使用------------------------------------ //查找第二个字母是 s 的名字name select name from tab where name like '_s%'; //查找第三个字母是 t 的名字name select name from tab where name like '__t%'; //找出name中带有 符号 _ 的值,要使用 \_ 进行转义 select name from tab where name like '%\_%';
select name,sal from tab order by sal;
select name,sal from tab order by sal desc;
select name,sal from tab order by sal asc;
sal asc
相等才能执行name asc
select name,sal from tab order by sal asc , name asc;
select .... from .... where .... order by ...
各关键字的执行顺序:
第一步:from ,第二步:where,第三步:select,第四步:order by (排序总是最后一步)
例如:找出工资在1250到3000之间的员工信息,要求按照薪资的降序排列
select name,sal from tab where sal between 1250 and 3000 order by sal desc;
数据处理函数又称为单行处理函数
单行处理函数的特点:一个输入对应一个输出
多行处理函数的特点:多个输入,对应一个输出
- lower 转换小写 - upper 转换大写 - substr 取子串,substr(字符串,起始下标,截取长度),起始下标从1开始 - length 计算长度 - concat 字符串拼接 - trim 去空格 - str_to_date 将字符串转日期,将varchar类型转为data类型 - date_format 格式化日期,将data类型转换为具有一定格式的varchar类型 - format 设置千分位 - round 四舍五入 - rand() 生成随机数 - ifnull 可以将null转换成一个具体的值 --> ifnull(数据,被当作哪个值),**null参数数学运算,输出结果都为null** - case...when...then...when...then...else...end 当什么时候做什么(不修改数据库,只是操作查询结果)
举个例子:
//lower 转换小写 Select lower(name) from tab; //upper 转换大写 Select upper(name) from tab; //concat 字符串拼接 select concat(name,sal) from tab; //length 取长度 select length(name) from tab; // trim 去空格 select name from tab where name = trim(' tree'); // round 四舍五入,0保留整数,-1保留到十位 select round(sal,0) from tab; //ifnull(数据,被当作哪个值),计算年薪 select (sal + ifnull(emp,0))*12 from tab; //case...when...then...when...then...else...end,当员工的工作岗位是MANGER时工资上调10%,为SAILSMAN时,工资上调50%,其他正常 select name, job, (case job when 'MANGER' then sal*1.1 when 'SAILSMAN' then sal*1.5 else sal end) as newsal from tab; ------------------稍微整合一下--------------------------- //首字母大写 select concat(upper(substr(name,1,1)),substr(name,2,length(name) - 1)) as result from tab;
str_to_date(‘字符日期’,‘日期格式’)
insert into t_user(id,name,birth) values(01,'jack',str_to_date('01-2-1999','%d-%m-%Y'));
date_format(日期类型数据,‘日期格式’)
select id, name, date_format(birth,'%m/%d/%Y') as birth from t_user;
多行处理函数的特点:输入多行,最终输出一行
注意:
在实际应用中,可能需要先进行分组,然后对每一组的数据进行操作,这时需要使用到分组查询。
select ... from ... where ... group by ... order by ...
执行顺序:from --> where --> group by --> select --> order by
为什么分组函数不能直接使用在where后面?
因为分组函数在使用的时候必须先分组在使用,where执行的时候,还没有分组。所以where后面不能出现分组函数。
使用having可以对分完组之后的数据进行进一步过滤,having不能单独使用,having不能代替where,having必须和group by联合使用
重点结论:
在一条select语句当中,如果有group by语句的话,select后面自能跟:参加分组的字段,以及分组函数,其他的一律不能跟。
//技巧:两个字段联合成1个字段来看 select depton,job,max(sal) from tab group by depton,job;
- 找出每个部门最高薪资,要求显示最高薪资大于3000的??
//写法一:使用having,效率较低 select depton,sal from tab group by depton having max(sal) > 3000; //写法二:使用where,where中不能使用分组函数 select depton,max(sal) from tab where sal > 3000 group by depton; /** *where和having,在where能够实现的情况下,首选where */
- 找出每个部门平均薪资,要求显示平均薪资大于2500??
//在where无法实现的情况下,才使用having select depton,avg(sal) from tab group by depton having avg(sal) > 2500;
查询语句格式顺序如下:
select ... from ... where ... group by ... having ... order by ...
- 执行顺序:from --> where --> group by --> having --> select --> order by
select job,avg(sal) as avgSal from tab where job <> 'MANAGER' group by job having avg(sal) > 1500 order by avgSal desc;
distinct --> 把查询结果,去除重复记录,只能出现在所有字段最前端
//distinct在job和name两个字段之前,表示将两个字段联合起来去重 select distinct job,name from tab;
跨表查询,多张表联合起来查询数据
根据表连接的方式分类:
两张表连接没有任何条件限制:
select dname,ename from etab,dtab;
当两张表进行连接查询,没有任何条件限制的时候,最终查询结果条数,是两张表条数的乘积,这种现象称为笛卡尔现象。
解决笛卡尔现象,查询次数没有减少。
select dname,ename from etab,dtab where etab.ename = dtab.dname;
表起别名,很重要,效率问题。
select d.dname, e.ename from etab e, dtab d where e.ename = d.dname;
注意:
通过笛卡尔积现象得出,表的连接次数越多效率越低,尽量避免表的连接次数。
A、B 两种表没有主次关系
例题:查询每个员工所在部门名称,显示员工名和部门名?
//SQL92语法,结构不清晰,和后期进一步筛选条件,都放在了where后面。 select e.name, d.dname from etab e, dtab d where e.depton = d.depton and 后面加条件; //SQL99语法 select e.name,d.dname from etab e inner join dtab d on e.depton = d.depton;
SQL99语法,表连接的条件是独立的,连接后,如果需要进一步筛选,再往后继续加where
//inner可以省略,可读性更好 select ... from a inner join b on a和b的连接条件 where 筛选条件;
例题:找出每个员工的薪资登记,要求显示员工名、薪资、薪资等级??
select e.ename ,e.sal ,s.grade from etab e join stab s on e.sal between s.losal and s.hisal;
例题:查询员工的上级领导,要求显示员工名和对应的领导名??(员工信息与领导信息都存在员工表中)
- 技巧:一张表看成两张表。
select e.name as '员工名', b.name as '领导名' from emp e join emp b on e.mgr = b.empo; //员工的领导编号 = 领导的员工编号
内连接的特点:完全能够匹配上这个条件的数据查询出来。
外连接特点:未匹配到的数据也可以查询出来。
right 代表:表示将join关键 右边 的这张表看成 主表,主要为了将这张表的数据 全部查出来,捎带着关联查询左边的表。
在外连接当中,两张表,产生了主次关系。
left 同理,左边 主表 全部查出来。
-----------------------右连接right----------------------------- //outer 可省略,带着可读性强 select e.ename, d.dname from etab e right outer join dtab d on e.depton = d.depton; -----------------------左连接left----------------------------- //outer 可省略 select e.ename, d.dname from etab e left join dtab d on e.depton = d.depton;
带有right的是右外连接,又称为右连接。
带有left的是左外连接,又称为左连接。
任何一个右连接都有左外连接的写法。
任何一个左外连接都有右外连接的写法。
外连接的查询结果条数一定大于内连接的查询结果条数。
select a.ename as '员工名' ,b.ename as '领导名‘ from etab a left join etab b on a.mgr = b.empno;
一条SQL中 内连接 和 外连接 可以混合使用。
select ... from a join b on //a和b 的连接条件 join c on //a和c 的连接条件 join d on //a和d 的连接条件
select e.ename,e.sal,d.dname,s.grade from emp e join dept d on e.deptno = d.deptno join salgrade s on e.sal between s.losal and s.hisal;
select e.ename, e.sal, d.dname, s.grade, l.ename from emp e join dept d on e.deptno = d.deptno join salgrade s on e.sal between s.losal and s.hisal left join emp l on e.mgr = l.empno;
- 什么是子查询?
select语句中嵌套select语句,被嵌套的select语句成为子查询。
子查询都可以出现在哪里??
select ...(select).. from ...(select).. where ...(select)..
//第一步,查询最低工资是多少 select min(sal) from emp; //第二步,找出>800的 select ename,sal,from emp where sal > 800; //第三步,合并 select ename,sal from emp where sal > (select min(sal) from emp);
- 注意:from后面的子查询,可以将子查询的查询结果当作一张临时表。
//先查询出每个岗位的平均工资 select job ,avg(sal) as avgsal from emp group by job; //将上面查询出的结果看作一张 表t,与 薪资表salgrade 进行连接查询 select t.*, s.grade from (select job ,avg(sal) as avgsal from emp group by job) t join salgrade s on t.avgsal between s.losal and s.hisal;
注意:select后面的子查询只能一次返回一条结果,多于一条,就报错。
select e.ename, (select d.name from dept d where e.deptno = d.deptno) as dname from emp e;
union的效率更高一些,对于表连接来说,每连接一次新表,则匹配的次数满足笛卡尔积,成倍的翻。
但是union可以减少匹配的次数。在减少匹配次数的情况下,还可以完成两个结果集的拼接。
select ename, job from emp where job = 'MANAGER'; union select ename, job from emp where job = 'SALESMAN';
- limit作用:将查询结果集的一部分取出来,通常使用在分页查询当中。
limit怎么使用: | |
---|---|
完整用法:limit startIndex length | |
startIndex是起始下标默认从0开始,length 是长度 | |
缺省用法:limit 5; 取前5条数据 |
select ename.sal from emp order by sal desc limit 0,5;
注意:limit是在order by 之后执行的!!!!
例题:取出工资排名在3-5名的员工???
select ename, sal from emp order by sal desc limit 2,3;
select ... from ... where ... group by ... having ... order by ... limit ...
执行顺序:
from --> where --> group by --> having --> select -->order by --> limit
create table 表名( 字段名1 数据类型, 字段名2 数据类型, 字段名3 数据类型 );
t_
或者 tab1_
开始,可读性强,见表名意create table emp2 as select * from emp; create table emp2 as select ename,empon from emp where jop = 'MANEGER';
常见的数据类型:
案例:创建一个学生表
create table t_student( no int, name varchar(35), sex char(1), default 'm', age int(3), email varchar(255) );
//直接删除,表不存在会报错 drop table t_student; //存在,再删除 drop table if exists t_student;
语法格式:
字段名和值要一一对应,数量对应,数据类型对应。
insert into 表名 (字段名1,字段名2,...) values(值1,值2,...);
- insert语句执行成功,必会多一条数据。 - 前面字段名都省略,等于都写上,后面所有值也要都写上 `insert into t_student values(2,'jack','m',20,'123@qq.com');`
insert into t_user(id,name,birth) values (01,'jack',now()), (02,'async',now()), (03,'luccy',now());
str_to_date(‘字符日期’,‘日期格式’)
insert into t_user(id,name,birth) values(01,'jack',str_to_date('01-2-1999','%d-%m-%Y'));
date_format(日期类型数据,‘日期格式’)
select id, name, date_format(birth,'%m/%d/%Y') as birth from t_user;
使用mysql函数获取系统当前时间:
语法格式:
update 表名 set 字段名1=值1,字段名2=值2,... where 条件; // 例子 update t_student set name = '张三', birth = '2000-10-11', creat_time = now() where no = 2;
语法格式:
delete from 表名 where 条件; //例子 delete from t_student where np = 2;
回滚操作:
start transaction; //开启事务 delete from dept_bak; //删除数据 rollback; //回滚恢复数据
//用法: truncate table dept_bak;
在创建的时候,我们可以给表中的字段加上一些约束,来保证这个表中数据的完整性、有效性!
非空约束not null约束的字段不能为NULL
create table t_vip( id int, name varchar(35) not null );
唯一性约束unique约束的字段不能重复,但是可以为NULL。
create table t_vip( id int, name varchar(35) unique, email varchar(255) );
create table t_vip( id int, name varchar(35), email varchar(255), unique(name,email) );
约束没有添加在列的后面,这种约束被称为表级约束。 需要给多个字段联合起来添加某一个约束的时候,需要使用表级约束。
在mysql中,某个字段同时被not null
和 unique
同时约束,该字段自动变为主键字段(oracle中不一样)
create table v_vip( id int, name varchar(35) not null unique //声明为主键PRI );
添加主键方法:
//使用主键约束 create table v_vip( //一个字段做主键,称为单一主键 id int primary key, name varchar(35) ); //使用表级约束 create table v_vip( id int, name varchar(35), primary key(id) ); create table v_vip( id int, name varchar(35), email varchar(255), //id和name联合起来做主键,复合主键,开发中不建议使用。 primary key(id,name) );
主键除了,单一主键和复合主键之外,还可以这样进行分类?
在mysql中,有一种机制,可以帮助我们自动维护一个主键值?
create table v_vip( //设置主键值为自增,从1开始自增 id int primary key auto_increment, name varchar(35), email varchar(255) );
例:创建学生和班级信息表??
t_student
表中的cno
的值只能是t_class
表中classno
的值//班级表,父表 create table t_class( classno int primary key, //班级编号,主键 classname varchar(255) //班级名称 ); //学生信息表,子表 create table t_student( no int primary key auto_increment, //学生编号,主键 name varchar(35), //学生名称 cno int, //班级编号 foreign key(cno) references t_class(classno) //添加外键约束 );
- 子表中的外键引用父表中的某个字段,被引用的字段不一定为主键,但至少具有
unique
约束。- 外键中的值可以为NULL。
给表添加指定的“存储引擎”
//查看表创建的结构 show create table t_student;
可以在建表的时候给表指定存储引擎
CREATE TABLE `user` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `username` varchar(20) NOT NULL, `password` varchar(20) NOT NULL, `gender` varchar(2) DEFAULT NULL, `email` varchar(50) DEFAULT NULL, `telephone` varchar(20) DEFAULT NULL, `introduce` varchar(100) DEFAULT NULL, `activeCode` varchar(50) DEFAULT NULL, `state` int(11) DEFAULT '0', `role` varchar(10) DEFAULT '普通用户', `registTime` timestamp(6) NULL DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4
在建表的时候可以在最后小括号的 “)” 的右边使用:
ENGINE来指定存储引擎
CHARSET来指定这张表的字符编码方式
结论:
可以在建表的时候声明存储引擎:
create table t_table( name varchar(35) primary key, age int(3) )engine=InnoDB default charset=gbk;
根据数据的版本,支持的存储引擎会有不同。
show engines \G
mysql支持9大存储引擎:
*************************** 1. row *************************** Engine: MEMORY Support: YES Comment: Hash based, stored in memory, useful for temporary tables Transactions: NO XA: NO Savepoints: NO *************************** 2. row *************************** Engine: MRG_MYISAM Support: YES Comment: Collection of identical MyISAM tables Transactions: NO XA: NO Savepoints: NO *************************** 3. row *************************** Engine: CSV Support: YES Comment: CSV storage engine Transactions: NO XA: NO Savepoints: NO *************************** 4. row *************************** Engine: FEDERATED Support: NO Comment: Federated MySQL storage engine Transactions: NULL XA: NULL Savepoints: NULL *************************** 5. row *************************** Engine: PERFORMANCE_SCHEMA Support: YES Comment: Performance Schema Transactions: NO XA: NO Savepoints: NO *************************** 6. row *************************** Engine: MyISAM Support: YES Comment: MyISAM storage engine Transactions: NO XA: NO Savepoints: NO *************************** 7. row *************************** Engine: InnoDB Support: DEFAULT Comment: Supports transactions, row-level locking, and foreign keys Transactions: YES XA: YES Savepoints: YES *************************** 8. row *************************** Engine: BLACKHOLE Support: YES Comment: /dev/null storage engine (anything you write to it disappears) Transactions: NO XA: NO Savepoints: NO *************************** 9. row *************************** Engine: ARCHIVE Support: YES Comment: Archive storage engine Transactions: NO XA: NO Savepoints: NO 9 rows in set (0.00 sec)
管理的表具有以下特征
可被转换为压缩、、只读表来节省空间。 (优点)
提示:对于一张表来说,只要是主键,或者加有unique约束的字段上会自动创建索引。
MyISAM不支持事务,安全性低。
mysql默认的存储引擎,同时也是一个重量级的存储引擎。
InnoDB支持事务,支持数据库崩溃后自动恢复机制。
InnoDB存储引擎最主要的特点是:非常安全。
管理的表具有一下主要特征:
innoDB最大的优点支持事务,以保证数据安全。
使用MEMORY存储引擎的表,其数据存储在内存中,且行的长度固定。
这两个特点使得MEMORY存储引擎非常快。
MEMORY 存储引擎管理的表具有一下特征:
MEMORY 存储索引以前被称为HEAP引擎。
一个事务就是一个完整的业务逻辑。是一个最小的工作单元,不可再分。
只有DML语句有事务一说,insert、update、delete,保证数据安全。
本质上,一个事务其实就是多条DML语句同时成功,或者同时失败。
提交事务: - 清空事务性活动的日志文件,将数据全部彻底持久化到数据库表中。 - 提交事务标志着,事务结束,并且是一种全部成功的结束。 回滚事务: - 将之前所有的DML操作全部撤销,并且清空事务性活动的日志文件。 - 回滚事务标志着,事务的结束,并且是一种全部失败的结束。
提交事务:commit; 语句
start transaction; //开启事务 .....//一系列DML语句 commit; //提交事务
回滚事务:rollback; 语句 (回滚只能回滚带上一次提交点)
start transaction; //开启事务 .....//一系列DML语句 rollback; //回滚事务
在mysql当中默认的事务行为:
关闭自动提交机制命令:
start transaction;
4个事务的隔离级别
//查看隔离级别 SELECT @@tx_isolation; //新版本已经弃用了 SELECT @@transaction_isolation; //新版本使用这个查看,mysql8.0+
read-uncommitted
//设置事务的隔离级别 mysql> set global transaction isolation level read uncommitted; //---------------------事务B操作--------------------------// mysql> start transaction; Query OK, 0 rows affected (0.00 sec) mysql> insert into t_user(name) values('wangwu'); Query OK, 1 row affected (0.01 sec) mysql> rollback; Query OK, 0 rows affected (0.00 sec) //---------------------事务A操作--------------------------// mysql> start transaction; Query OK, 0 rows affected (0.00 sec) mysql> select * from t_user; //在事务B 操作事务未提交,就读取到数据 +--------+ | name | +--------+ | wangwu | +--------+ 1 row in set (0.00 sec) mysql> select * from t_user; //当事务B 执行rollback回滚事务后,事务A 中的数据就没了 Empty set (0.00 sec)
read-committed
mysql> set global transaction isolation level read committed; //---------------------事务B 操作--------------------------// mysql> start transaction; Query OK, 0 rows affected (0.00 sec) mysql> insert into t_user values('zhangsan'); //执行insert ,但未提交事务 Query OK, 1 row affected (0.00 sec) mysql> commit; //提交事务 Query OK, 0 rows affected (0.00 sec) //---------------------事务A 操作--------------------------// mysql> start transaction; Query OK, 0 rows affected (0.00 sec) mysql> select * from t_user; //事务B 执行insert之前 Empty set (0.00 sec) mysql> select * from t_user; //事务B 执行insert之后 Empty set (0.00 sec) mysql> select * from t_user; //事务B commit提交事务后,执行 +----------+ | name | +----------+ | zhangsan | +----------+ 1 row in set (0.00 sec)
repeatable-read
mysql> set global transaction isolation level repeatable read; //---------------------事务B 操作--------------------------// mysql> start transaction; //开启事务 Query OK, 0 rows affected (0.00 sec) mysql> select * from t_user; //先查询表中数据 +----------+ | name | +----------+ | zhangsan | +----------+ 1 row in set (0.00 sec) //向t_user表中,插入3条数据 mysql> insert into t_user(name) values('jack'),('wangwu'),('daniu'); Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> select * from t_user; +----------+ | name | +----------+ | zhangsan | | jack | | wangwu | | daniu | +----------+ 4 rows in set (0.00 sec) mysql> commit; //提交事务 Query OK, 0 rows affected (0.00 sec) //---------------------事务A 操作--------------------------// mysql> start transaction; //开启事务 Query OK, 0 rows affected (0.00 sec) mysql> select * from t_user; //事务B,执行insert之前查询 +----------+ | name | +----------+ | zhangsan | +----------+ 1 row in set (0.00 sec) mysql> select * from t_user; //事务B,执行insert之后查询 +----------+ | name | +----------+ | zhangsan | +----------+ 1 row in set (0.00 sec) mysql> select * from t_user; //事务B,执行commit 提交事务后查询 +----------+ | name | +----------+ | zhangsan | +----------+ 1 row in set (0.00 sec)
serializable
mysql> set global transaction isolation level serializable; //---------------------事务B 操作--------------------------// mysql> start transaction; Query OK, 0 rows affected (0.00 sec) mysql> select * from t_user; +----------+ | name | +----------+ | zhangsan | | jack | | wangwu | | daniu | +----------+ 4 rows in set (0.00 sec) //---------------------事务A 操作--------------------------// mysql> start transaction; Query OK, 0 rows affected (0.00 sec) mysql> select * from t_user; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql>_ //当事务B 的操作未提交commit时,事务A 的操作无法进行操作。 //当事务B 将事务提交commit后,事务A 才能继续执行。 +--------------------+ | name | +--------------------+ | zhangsan | | jack | | wangwu | | daniu | | serializableUser | | serializableUser22 | +--------------------+ 6 rows in set (0.00 sec)
索引是在数据库表的字段上添加的,是为了提高查询效率存在一种机制。
一张表的一个字段可以添加一个索引,当然,多个字段联合起来也可以添加索引。
在MySQL数据库当中索引也需要排序,并且这个索引的排序和TressSet数据结构相同。TreeSet(TreeMap)底层是一个自平衡的二叉树! 在mysql当中索引是一个B-Tree数据结构。
遵循左小右大原则存放,采用中序遍历方式遍历取数据。
缩小扫描范围,避免全表扫描。
提醒1:在任何数据库当中主键上都会自动添加索引对象,id字段上自动有索引。因为id是PK。另外在MySQL当中,一个字段上如果有unique约束的话,也会自动创建索引对象。
提醒2:在任何数据库当中,任何一张表的任何一条记录在硬盘上都有一个硬盘的物理存储编号。
提醒3:在mysql当中,索引是一个单独的对象,不同的存储引擎以不同的形式存在。在MyISAM存储引擎中,索引存储在一个.MYI文件中。在InnDB存储引擎中,索引存储在一个逻辑名称叫做tablespace的当中。在MEMORY存储引擎中,索引被存储在内存当中。不管索引存储在哪里,索引在mysql当中都是一个树的形势存在。(平衡二叉树:B-Tree)
举个例子:
添加索引条件: - 数据量庞大 - 该字段经常出现在where后面,以条件的形式存在,也就是说这字段总是被扫描。 - 该字段很少的DML操作,因为DML之后,索性需要重新排序。
建议不要随意添加索引,因为索引也需要维护,太多的话反而会降低系统的性能。
建议通过主键查询,通过unique约束的字段进行查询,效率比较高。
//给emp表的ename字段添加索引,起名:emp_ename_index create index emp_ename_index on emp(ename); //删除索引 drop index emp_ename_index on emp;
//使用explain 查看语句查询方式 mysql> explain select * from user where email ='19747708@qq.com'; +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ | 1 | SIMPLE | user | NULL | ALL | NULL | NULL | NULL | NULL | 5 | 20.00 | Using where | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ 1 row in set, 1 warning (0.00 sec)
rows=5扫描了5条记录,type=ALL,说明没有使用索引。
//创建索引 create index email_index on user(email); //使用explain 查看语句查询方式 mysql> explain select * from user where email ='19747708@qq.com'; +----+-------------+-------+------------+------+---------------+-------------+---------+-------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+-------------+---------+-------+------+----------+-------+ | 1 | SIMPLE | user | NULL | ref | email_index | email_index | 203 | const | 1 | 100.00 | NULL | +----+-------------+-------+------------+------+---------------+-------------+---------+-------+------+----------+-------+ 1 row in set, 1 warning (0.01 sec)
rows=1扫描了1条记录,type=ref ,说明使用索引。
情况1:
避免使用模糊查询的时候以“%”开始,这是一种优化策略。
mysql> explain select * from user where email like '%708'; +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ | 1 | SIMPLE | user | NULL | ALL | NULL | NULL | NULL | NULL | 5 | 20.00 | Using where | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ 1 row in set, 1 warning (0.00 sec)
情况2:
使用or的时候会失效如果使用or那么要求两边的条件都要有索引,才会走索引,如果其中一边有一个字段没有索引,那么另外一个字段上的索引也会失效,所以不建议使用or。
mysql> explain select * from user where email = '19747708@qq.com' or telephone ='12345678911 '; +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ | 1 | SIMPLE | user | NULL | ALL | email_index | NULL | NULL | NULL | 5 | 36.00 | Using where | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ 1 row in set, 1 warning (0.00 sec)
情况3:
使用复合索引的时候,没有使用左侧的列查找,索引失效。
复合索引:两个字段,或者更多的字段联合起来添加一个索引。
create index role_name on user(role,username); //--------------左侧索引 role---------------------// mysql> explain select * from user where role = '普通用户'; +----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------+ | 1 | SIMPLE | user | NULL | ref | role_name | role_name | 43 | const | 3 | 100.00 | NULL | +----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------+ 1 row in set, 1 warning (0.00 sec) //--------------右侧索引 username-----------------// mysql> explain select * from user where username = 'as123'; +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ | 1 | SIMPLE | user | NULL | ALL | NULL | NULL | NULL | NULL | 5 | 20.00 | Using where | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ 1 row in set, 1 warning (0.00 sec)
情况4:
在where当中索引列参加了数学运算,索引失效。
mysql> create index state_index on user(state); //-------------未添加数学运算----------------// mysql> explain select * from user where state = 1; +----+-------------+-------+------------+------+---------------+-------------+---------+-------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+-------------+---------+-------+------+----------+-------+ | 1 | SIMPLE | user | NULL | ref | state_index | state_index | 5 | const | 1 | 100.00 | NULL | +----+-------------+-------+------------+------+---------------+-------------+---------+-------+------+----------+-------+ 1 row in set, 1 warning (0.00 sec) //-------------添加数学运算----------------// //索引 列 state参加数学运算 mysql> explain select * from user where state+1 = 1; +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ | 1 | SIMPLE | user | NULL | ALL | NULL | NULL | NULL | NULL | 5 | 100.00 | Using where | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ 1 row in set, 1 warning (0.00 sec)
情况5:
在where当中索引列使用了函数。
mysql> drop index role_name on user; mysql> create index name_index on user(username); //----------------------------------未添加函数---------------------------------// mysql> explain select * from user where username = 'asd123'; +----+-------------+-------+------------+------+---------------+------------+---------+-------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------------+---------+-------+------+----------+-------+ | 1 | SIMPLE | user | NULL | ref | name_index | name_index | 82 | const | 1 | 100.00 | NULL | +----+-------------+-------+------------+------+---------------+------------+---------+-------+------+----------+-------+ 1 row in set, 1 warning (0.00 sec) //----------------------------------添加函数---------------------------------// mysql> explain select * from user where lower(username) = 'asd123'; +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ | 1 | SIMPLE | user | NULL | ALL | NULL | NULL | NULL | NULL | 5 | 100.00 | Using where | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ 1 row in set, 1 warning (0.00 sec)
索引是各种数据库进行优化的重要手段。优化优先考虑索引。
站在不同角度去看待同一份数据。
create view user2_view as select * from user;
drop view user2_view;
//对user2_view 视图进行插入操作 mysql> insert into user2_view(username,password,gender,email) values('jjjj','sss','m','123@qq.com'); Query OK, 1 row affected (0.00 sec) //查询原表数据,发生改变 mysql> select * from user2; +----+------------+----------+--------+--------------------+-------------+------------------+------------+-------+----------+----------------------------+ | id | username | password | gender | email | telephone | introduce | activeCode | state | role | registTime | +----+------------+----------+--------+--------------------+-------------+------------------+------------+-------+----------+----------------------------+ | 1 | | | NULL | NULL | NULL | NULL | NULL | 0 | NULL | 0000-00-00 00:00:00.000000 | | 3 | as123 | 123456 | 男 | 1974708999@qq.com | 17706058702 | fddfds | NULL | 0 | 普通用户 | 2020-06-13 00:00:00.000000 | | 4 | sasassa123 | 654321 | 男 | 1974708999@163.com | 17706058703 | asdasff | NULL | 0 | 普通用户 | NULL | | 5 | tti_12 | 987654 | 男 | 1421842575@12.com | 12346789112 | 测试账户登录账号 | NULL | 0 | 普通用户 | NULL | | 6 | al_22 | 159753 | 男 | 1974708999@123.com | 12345678911 | 验证信息123 | NULL | 1 | 超级用户 | NULL | | 0 | jjjj | sss | m | 123@qq.com | NULL | NULL | NULL | 0 | 普通用户 | NULL | +----+------------+----------+--------+--------------------+-------------+------------------+------------+-------+----------+----------------------------+ 6 rows in set (0.00 sec)
重点掌握数据的导入导出(数据备份)
数据的导出:
mysqldump bjpowernode>D:\bjpowernode.sql -uroot -p123
mysqldump bjpowernode table>D:\bjpowernode.sql -uroot -p123
数据导入
create database bjpowernode;
use bjpowernode;
source D:\bjpowernode.sql
最核心,最重要的范式,所有表的设计都需要满足。
必须要有主键,并且每一个字段都是原子性不可拆分。
建立在第一范式的基础上,要求所有非主键字段必须完全依赖主键,不要产生部分依赖。
多对多设计:多对多,三张表,关系表两个外键。
第三范式建立在第二范式的基础上,要求所有非主键字段必须直接依赖主键,不要产生传递依赖。
一对多设计:两张表,多的表加外键。
在实际开发中,可能存在一张表字段太多,太庞大,这时候需要拆分表。
总结:
- 数据库设计三范式是理论上的。
- 在MySQL当中,表和表之间连接次数越多,效率越低。(笛卡尔集)
- 有时候可能存在冗余,但是为了减少表的连接次数,这样做也是合理的。并且对于开发人员来说,sql语句的编写难度也会降低。