个人网站: 【紫陌】【笔记分享网】
想寻找共同学习交流、共同成长的伙伴, 请点击【前端学习交流群】
目录
1.创建数据库
2.创建,删除表和使用表
2.1介绍表
2.2创建表
2.3删除表
2.2.1 SQL server中的数据类型
2.3更新表
2.3.1添加列(字段)
2.3.2删除列(字段)
2.4查询表
2.4.1查询单个字段
2.4.2查询多个字段
2.4.3查询整个表
2.4.5查询排序数据【order by】
2.5.6过滤数据【where】
2.5.7数据处理函数
2.5.8分组查询
2.5.9使用子查询
2.5连接查询
2.5.1 内连接之非等值连接
2.5.2内连接之非等值连接
2.5.3内连接之自连接
2.5.4外连接(右外连接)
2.5.5外连接(左外连接)
2.5.6 union合并查询结果集
2.6 top(类似mysql的limit)
2.7表的查询学完了(总结)
2.8插入数据insert
2.9修改update
2.10删除数据 delete
2.11表复制
3.视图(view)
4.约束(constraint)
1.约束的作用?
2.约束包括哪些?
1.非空约束 not null
2.唯一性约束:unique
3.主键约束(primary key,简称PK)
4.外键约束 foreign key 简称 fk(重点)
5.检查约束(CHECK)
6.默认约束(DEFAULT )
5.事务(重点)
5.1认识事务
5.2事务的实现
5.3怎么提交事务,怎么回滚事务?
5.4事务的4个特性
6.索引
6.1索引的实现原理
6.2创建和删除索引
6.3索引的失效
7.0 数据库三范式
create datatbase 数据库名称
数据库最基本的单元是表:table
什么是表table?为什么用表来存储数据呢?
姓名 性别 年龄(列:字段)
---------------------------
张三 男 20 ------->行(记录)
李四 女 21 ------->行(记录)
王五 男 22 ------->行(记录)
数据库当中是以表格的形式表示数据的。
因为表比较直观。
任何一张表都有行和列:
行(row):被称为数据/记录。
列(column):被称为字段。
姓名字段、性别字段、年龄字段。
了解一下:
每一个字段都有:字段名、数据类型、约束等属性。
字段名可以理解,是一个普通的名字,见名知意就行。
数据类型:字符串,数字,日期等,后期讲。
约束:约束也有很多,其中一个叫做唯一性约束,
这种约束添加之后,该字段中的数据不能重复。
# 语法
create table table_name(
字段名称1 字段类型 [default 默认值] [not null],--非空存在默认值
字段名称2 字段类型 [primary key],--主键
字段名称3 字段类型 [foreign key references table_name(字段名称)],--外键
字段名称4 字段类型 check(限制条件)--设置有约束
)
表名:建议以t_ 或者 tbl_开始,可读性强。见名知意。
字段名:见名知意。
表名和字段名都属于标识符。
代码示例:
创建一个学生表?
create table 学生表(
学号 nchar(5) primary key,
性别 nchar(1) check(性别='男' or 性别='女'),
班级号 ncahr(3) foreign key references 班级表(班级号),
爱好 nvarchar(100) default '无'
)
注意:
1、在同一张表中,字段名不能相同
2、宽度 和 约束条件为可选参数,字段名 和 字段名下记录的类型 是必须的
3、最后一个字段后不能加逗号
drop table 学生表
很多数据类型,我们只需要掌握一些常见的数据类型即可。
1.字符型:
varchar(8000)
可变长度的字符串
比较智能,节省空间。
会根据实际的数据长度动态分配空间。
优点:节省空间
缺点:需要动态分配空间,速度慢。
char(8000)
定长字符串
不管实际的数据长度是多少。
分配固定长度的空间去存储数据。
使用不恰当的时候,可能会导致空间的浪费。
优点:不需要动态分配空间,速度快。
缺点:使用不当可能会导致空间的浪费。
varchar和char我们应该怎么选择?
性别字段你选什么?因为性别是固定长度的字符串,所以选择char。
姓名字段你选什么?每一个人的名字长度不同,所以选择varchar。
text 可变长度字符串 2GB
nchar(n) 40000
nvarchar(n) 4000 2字节
nvarchar(max) varchar长度1/2
ntext
注意:前面带n,存储中文汉字还是英文或数字,长度都是1,存储大小2个字节,不带n,英文或数字,就是1个长度,中文就是两个长度
unicode 字符串
2.日期型
datetime 精确度高,
datetime2 精度更高,100纳秒
smalldatetime 精度1分钟 时间范围小
date 存储日期
time 存储时间
3.其他类型
uniqueidentifier guid 全球唯一标识符。
语法:
alter table table_name add 列名 字段类型
示例:
alter table 表名 add 列名 nchar(30);
注意:
在实际的开发中,需求一旦确定之后,表一旦设计好之后,很少的
进行表结构的修改。因为开发进行中的时候,修改表结构,成本比较高。
修改表的结构,对应的java代码就需要进行大量的修改。成本是比较高的。
这个责任应该由设计人员来承担!
语法:
alter table table_name
drop column 字段名
示例:
alter table 学生表
drop column 学号
语法:
select 字段名 from table_name
示例:
select 姓名 from 员工表
语法:
select 字段名1,字段名2 from table_name
示例:
select 姓名,性别 from 员工表
语法:
select * from table_name
示例:
select * from 员工表
这种方式的缺点:
1、效率低
2、可读性差。
在实际开发中不建议,可以自己玩没问题。
2.4.4把查询结果去除重复记录【distinct】
语法:
select distinct 字段名 from table_name
示例:
select distinct 性别 from 员工表
注意:原表数据不会被修改,只是查询结果去重。
按一个字段排序
语法:
select 字段名 from table_name order by 字段名
示例:
select 身高 from 学生表 order by 身高
按多个字段排序
语法:
select 字段名1,字段名2 from table_name order by 字段名1,字段名2
示例:
select 字段名1,字段名2 from 学生表 order by 字段名1,字段名2
指定排序方向
语法:
--升序排列
select 字段名 from table_name order by 字段名 asc
--降序排列
select 字段名 from table_name order by 字段名 desc
示例:
--升序排列
select 身高 from 学生表 order by 身高 asc
--降序排列
select 身高 from 学生表 order by 身高 desc
使用where语句
语法:
select 字段名1,字段名2 from table_name where 限制条件
示例:
select *from 学生表 where 性别 = '男'
不匹配检查
语法:
select 字段名1,字段名2 from 学生表 where 字段名 <> 某个值
示例:
列出不是团员的所有学生信息
select *from 学生表 where 党员 <> 1
注意:!= 和 <> 通常可以互换,但是并不是所有的DBMS都支持这两种不等于操作符。
示例:
列出不是团员的所有学生信息
select *from 学生表 where 团员 <> 1
范围值检查
在where子句中使用between…and…between匹配范围中所有的值,包括指定的开始值和结束值
示例:
查找身高在1.60~1.70之间的学生信息
select *from 学生表 where 身高 between 1.50 and 1.80
空值检查
语法:
当一个列不包含值时,称其包含空值NULL
示例:
使用select语句的is null子句来检查空值
select *from 学生表 where 性别 is null
组合where语句
(and操作符)
语法:
要通过不止一个列进行过滤,可以使用and操作符给where子句附加条件
示例:
select *from 学生表 where 性别 = '男' and 团员 = 1
or操作符
语法:
or操作符与and操作符正好相反,它指示检索匹配任一条件的行。
示例:
select *from 学生表 where 性别 = '男' or 团员 = 1
求值顺序
where子句可以包含任意数目的and和or操作符。允许两者结合以进行复杂、高级的过滤。
示例:
select *from 学生表 where (性别 = '女' or 团员 = 1) and 身高 > 1.70
注意:SQL在处理or操作符前,优先处理and操作符,即and在求值过程中优先级更高。
in操作符
语法:
in操作符用来指定条件范围,范围中的每个条件都可以进行匹配
in取一组由逗号分隔、括在圆括号中的合法值。
示例:
select *from 学生表 where 身高 in ('1.60','1.55','1.75')
not 操作符
语法:
where子句的not操作符有且只有一个功能,否定器后所跟的任何条件
not关键字可以用在要过滤的列前,而不是列后。
示例:
select *from 学生表 where not 团员 = 1
like关键字
称为模糊查询,支持%或下划线匹配
%匹配任意多个字符
下划线:任意一个字符。
(%是一个特殊的符号,_ 也是一个特殊符号)
找出名字中含有A的
select 字段名 from 表名 where 字段名 like '%A%';
找出名字以T结尾的
select 字段名 from 表名 where 字段名 like '%T';
找出名字以G开始的
select 字段名 from 表名 where 字段名 like 'G%';
找出第二个字每是C的?
select 字段名 from 表名 where 字段名 like '_C%';
数据处理函数又被称为单行处理函数
单行处理函数的特点:一个输入对应一个输出。
和单行处理函数相对的是:多行处理函数。(多行处理函数特点:多个输入,对应1个输出!)
常用的文本处理函数:
函数 |
说明 |
left() |
返回字符串左边的字符 |
length() |
返回字符串长度 |
lower() |
将字符串转换为小写 |
ltrim() |
去掉字符串左边的空格 |
right() |
返回字符串右边的字符 |
rtrim() |
去掉字符串右边的空格 |
soundex() |
返回字符串的soundex值 |
substr() 或substring() |
提取字符串的组成部分 |
upper() |
将字符串转换为大写 |
分组函数(多行处理函数)
多行处理函数的特点:输入多行,最终输出一行。
注意:
分组函数在使用的时候必须先进行分组,然后才能用。
如果你没有对数据进行分组,整张表默认为一组。
函数 |
说明 |
avg() |
返回某列的平均值 |
count() |
返回某列的行数 |
max() |
范恢复某列的最大值 |
min() |
返回某列的最小值 |
sum() |
返回某列之和 |
AVG()函数
AVG()通过对表中行数计数并计算其列值之和,求得该列的平均值。
AVG()可以用来返回所有列的平均值,也可以用来返回特定列或行的平均值。
示例:
求出成绩表中的平均成绩:
select AVG(成绩) as 平均成绩 from 成绩表
COUNT()
COUNT()函数进行计数
示例:
求出学生表中的总人数
select COUNT(*) as 总人数 from 学生表
注意:
1.使用COUNT(*)对表中的数据数目进行计数,不管表列中包含的是空值(NULL)还是非空值
2.使用COUNT(column)对特定列中具有值得行进行计数,忽略NULL值
组合分组函数
select语句可以根据需要包含多个分组函数
示例:
select COUNT(*) as 商品数目
MIN(价格) as 最低商品价格
MAX(价格) as 最高商品价格
AVG(价格) as 商品均价
from 商品表
分组:
是使用select语句的group by子句建立的
求出每种商品的商品数量
select 商品名,COUNT(*) as 商品数量
from 商品表
group by 商品名
重点结论:
过滤分组(having)
where过滤行,having过滤分组
having支持所有where操作符
示例:
示例:
求出商品数量大于等于2的商品数量
select 商品名,COUNT(*) as 商品数量
from 商品表
group by 商品名
having COUNT(*)>=2
where在数据分组前进行过滤,having在数据分组后进行过滤
子查询:
select语句中嵌套select语句,被嵌套的select语句称为子查询。
利用子查询进行过滤
在select 中子查询总是从内向外进行处理,作为子查询的select语句只能查询单个列
示例:
select
..(select).
from
..(select).
where
..(select)
select * from 选课表 where 学号 in
(select 学号 from 学生表 where 性别 = '男')
什么是连接查询?
从一张表中单独查询,称为单表查询。 emp表和dept表联合起来查询数据,从emp表中取员工名字,从dept表中取部门名字。 这种跨表查询,多张表联合起来查询数据,被称为连接查询。
根据表连接的方式分类:
内连接:
等值连接
非等值连接
自连接
外连接:
左外连接(左连接)
右外连接(右连接)
全连接
当两张表进行连接查询时,没有任何条件的限制会发生什么现象?
当两张表进行连接查询,没有任何条件限制的时候,最终查询结果条数,是两张表条数的乘积,这种现象被称为:笛卡尔积现象。(笛卡尔发现的,这是一个数学现象。)
怎么避免笛卡尔积现象?
连接时加条件,满足这个条件的记录被筛选出来!
语法:
select 员工表的员工名字,部门表的部门名
from 员工表,部门表
where 员工表.名字=部门表.部门名
示例:
select
emp.ename,dept.dname
from
emp, dept
where
emp.deptno = dept.deptno;
注意:通过笛卡尔积现象得出,表的连接次数越多效率越低,尽量避免表的连接次数
--inner可以省略(带着inner可读性更好!!!一眼就能看出来是内连接)
select
e.ename,d.dname
from
emp e -- as省略了,给字段起别名,效率更高
inner join
dept d
on
e.deptno = d.deptno; -- 条件是等量关系,所以被称为等值连接。
案例:找出每个员工的薪资等级,要求显示员工名、薪资、薪资等级?
select
e.ename, e.sal, s.grade
from
emp e
join
salgrade s
on
e.sal between s.losal and s.hisal; // 条件不是一个等量关系,称为非等值连接。
案例:查询员工的上级领导,要求显示员工名和对应的领导名?
emp a 员工表 emp b 领导表
select
a.ename as '员工名', b.ename as '领导名'
from
emp a
join
emp b
on
a.mgr = b.empno; --员工的领导编号 = 领导的员工编号
以上就是内连接中的:自连接,技巧:一张表看做两张表
注意:
内连接:(A和B连接,AB两张表没有主次关系。平等的。)
语法:
select 员工表.员工名,部门表.部门名
from 员工表 right join 部门表 on 员工表.编号=部门表.编号
语法
-- outer是可以省略的,带着可读性强。
select
e.ename,d.dname
from
emp e
right outer join
dept d
on
e.deptno = d.deptno;
right代表什么:表示将join关键字右边的这张表看成主表,主要是为了将 这张表的数据全部查询出来,捎带着关联查询左边的表。 在外连接当中,两张表连接,产生了主次关系。
语法:
select 员工表.员工名,部门表.部门名
from 部门表 right join 员工表 on 员工表.编号=部门表.编号
-- outer是可以省略的,带着可读性强。
select
e.ename,d.dname
from
dept d
left outer join
emp e
on
e.deptno = d.deptno;
带有right的是右外连接,又叫做右连接。
带有left的是左外连接,又叫做左连接。
任何一个右连接都有左连接的写法。
任何一个左连接都有右连接的写法。
三张表,四张表怎么连接?
语法:
select
...
from
a
join
b
on
a和b的连接条件
join
c
on
a和c的连接条件
right join
d
on
a和d的连接条件
语法;
select 字段名1,字段名2,字段名3
from table_name
where 限制条件1
union
select 字段名1,字段名2,字段名3
from table_name
where 限制条件2
示例:
select 姓名,性别
from 学生表
where 学号 in ('01','02','03')
union
select 姓名,性别
from 学生表
where 学号 ='04'
注意:union的效率要高一些。对于表连接来说,每连接一次新表,则匹配的次数满足笛卡尔积,成倍的翻。但是union可以减少匹配的次数。在减少匹配次数的情况下,还可以完成两个结果集的拼接。
在SQL Server中,不支持 Limit 语句。
解决方案:
虽然SQL Server不支持 Limit ,但是它支持 TOP。
案例:
要查询前6条记录
select top 6 字段 from 表名
要查询第 3 条到第 10 条记录
select top 8 id from 表名
where 字段名1 not in (
select top 2 字段名1 from 表名
)
取第m条到第n条记录:
select top (n-m+1) id from tablename
where id not in (
select top m-1 id from tablename
)
按照薪资降序,取出排名在前5名的员工?
select
ename,sal
from
emp
order by
sal desc
limit 5; --取前5
缺省用法:limit 5; 这是取前5.
注意:mysql当中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
...
以上关键字只能按照这个顺序来,不能颠倒。
执行顺序?
1.from
2.where
3.group by
4.having
5.select
6.order by
7.limit..
从某张表中查询数据,
先经过where条件筛选出有价值的数据。
对这些有价值的数据进行分组。
分组之后可以使用having继续筛选。
select查询出来。
最后排序输出!
语法格式:
insert into 表名(字段名1,字段名2,字段名3...) values(值1,值2,值3);
insert语句中的“字段名”可以省略
注意:前面的字段名省略的话,等于都写上了!所以值也要都写上!
语法:
insert into table_name
values(值1, 值2,....)
示例:
insert into 学生表01
values('李明','男','1.70')
语法:
update table_name
set
字段名1='值',
字段名2='值'
where 限制条件
示例:
update 学生表
set
姓名='小红',
性别='女'
where 学号='01'
注意:没有条件限制会导致所有数据全部更新。
语法;
delete from table_name
where 要删除行的信息
示例:
delete from 学生表
where 学号='01'
快速删除表中的数据?【truncate比较重要,必须掌握】
--删除dept_bak表中的数据
delete from dept_bak; --这种删除数据的方式比较慢。
用法:truncate table dept_bak; (这种操作属于DDL操作。)
删除表操作?
drop table 表名; -- 这不是删除表中的数据,这是把表删除。
delete语句删除数据的原理?(delete属于DML语句!!!)
表中的数据被删除了,但是这个数据在硬盘上的真实存储空间不会被释放!!!
这种删除缺点是:删除效率比较低。
这种删除优点是:支持回滚,后悔了可以再恢复数据!!!
truncate语句删除数据的原理?
这种删除效率比较高,表被一次截断,物理删除。
这种删除缺点:不支持回滚。
这种删除优点:快速。
大表非常大,上亿条记录?
删除的时候,使用delete,也许需要执行1个小时才能删除完!效率较低。
可以选择使用truncate删除表中的数据。只需要不到1秒钟的时间就删除结束。效率较高。
但是使用truncate之前,必须仔细询问客户是否真的要删除,并警告删除之后不可恢复!
truncate是删除表中的数据,表还在!
create table dept2 as select * from dept;
什么是视图?
view:站在不同的角度去看待同一份数据。
数据库中的建立的表table叫物理表
view是查询结果的保存,它是虚拟表
怎么创建视图对象?
语法:
create view table_name as
select 创建视图的相应信息
示例:
create view 学生成绩表 as
select 学生表.学号,课程名称,成绩
from 学生表,成绩表,课程表
where 学生表.学号 = 成绩表.学号
and 成绩表.课程编号 = 课程表.课程编号
用视图做什么?
我们可以面向视图对象进行增删改查,对视图对象的增删改查,会导致原表被操作!(视图的特点:通过对视图的操作,会影响到原表数据。)
视图对象在实际开发中到底有什么用?
《方便,简化开发,利于维护》
假设有一条非常复杂的SQL语句,而这条SQL语句需要在不同的位置上反复使用。
每一次使用这个sql语句的时候都需要重新编写,很长,很麻烦,怎么办?
可以把这条复杂的SQL语句以视图对象的形式新建。
在需要编写这条SQL语句的位置直接使用视图对象,可以大大简化开发。
并且利于后期的维护,因为修改的时候也只需要修改一个位置就行,只需要
修改视图对象所映射的SQL语句。
我们以后面向视图开发的时候,使用视图的时候可以像使用table一样。
可以对视图进行增删改查等操作。视图不是在内存当中,视图对象也是
存储在硬盘上的,不会消失。
再提醒一下:
视图对应的语句只能是DQL语句。
但是视图对象创建完成之后,可以对视图进行增删改查等操作。
在创建表时我们需要给表中的字段增加一些约束,来保证表数据的完整性,有效性
非空约束所约束的字段不能为null。
ALTER TABLE 数据表名称
ALTER COLUMN ID INT NOT NULL
唯一性约束unique约束的字段不能重复,但是可以为NULL。
ALTER TABLE 数据表名称
ADD CONSTRAINT QU_Name --(命名一个唯一约束的名称)
UNIQUE([Name])
主键约束的相关术语:主键约束、主键字段、主键值。
主键值是每一行记录的唯一标识。
注意:任何一张表都应该有主键,没有主键,表无效!
主键的特征:not null + unique(不能为空,同时不能重复)
添加主键约束:
ALTER TABLE 数据表名
ADD CONSTRAINT PK_ID --(命名一个主键名称)
PRIMARY KEY(ID)
当两张表有父子关系时,子表上与父表关联的字段为保证数据有效需要加外键约束,被引用的字段可以不是主键可以为null但是必须具有唯一性
ALTER TABLE 从表名称
ADD CONSTRAINT FK_SID --(命名一个外键名称)
--添加外键约束
FOREIGN KEY(StuID) REFERENCES 主表名称(ID)
设置这个字段中的数据特性
ALTER TABLE 数据表名称
ADD CONSTRAINT CK_SEX --(命名一个检查约束的名称)
CHECK(SEX IN('男','女'));
若在表中定义了默认值约束,用户在插入新的数据行时,如果该行没有指定数据,那么系统将默认值赋给该列,如果我们不设置默认值,系统默认为NULL。
1. 如果表字段已经建好
--DF_XXX(命名一个默认约束的名称)
ALTER TABLE 表名
ADD CONSTRAINT DF_XXX DEFAULT 1 FOR 字段名
2.如果表字段没有建
ALTER 表名 ADD 字段名 INT DEFAULT(1)
删除约束
--删除检查约束
ALTER TABLE 数据表名称
DROP CONSTRAINT CK_AGE --(你想要删除的某个键名或者约束名称)
一个事务其实就是一个完整的业务逻辑,是一个最小的工作单元。要么同时成功,要么同时失败,不可再分。
假设转账,从A账户向B账户转账10000
A账户的钱减去10000(update语句)
B账户的钱加上10000(update语句)
这就是一个完整的业务逻辑
这两个update语句要求必须同时成功或者同时失败,才能保证钱是正确的。
只有DML语句才会有事务这一说,其他语句和事务无关。
insert、delete、update。
一旦你的操作涉及到增、删、改,那么就一定要考虑安全问题。
事务:就是批量的DML语句同时成功,或者同时失败。
事务是怎么做到多条DML语句同时成功和同时失败的?
InnoDB存储引擎:提供一组用来记录事务性活动的日志文件。
事务开启:
insert
delete
update
…
事务结束
在事务执行过程中。每一条DML的操作都会记录到“事务性活日志文”中
在事务执行过程中我们可以提交事务也可以回滚事务
提交事务:清空事务性活动的日志文件,将数据全部彻底持久化到数据库表中,标志着事物成功结束
回滚事务:清空事务性活动的日志文件,将所有的DML操作全部撤销,标志着事务失败结束
提交事务:commit
回滚事务:rollback
mysql默认情况下自动提交事务,那怎么自己提交事务呢?
START TRANSACTION;
SELECT * FROM dept;
START TRANSACTION;
INSERT INTO dept VALUE(50,'jjj','yyyy');
SELECT * FROM dept;
ROLLBACK;
SELECT * FROM dept;
事务一旦提交回滚就没有作用
SELECT * FROM dept;
START TRANSACTION;
INSERT INTO dept VALUE(50,'jjj','yyyy');
SELECT * FROM dept;
COMMIT;
ROLLBACK;
SELECT * FROM dept;
ACID
事务与事务之间有4个隔离级别
索引是在数据库表的字段上添加的,是为了提高查询效率存在的一种机制。
一张表的一个字段可以添加一个索引,当然,多个字段联合起来也可以添加索引。
索引相当于一本书的目录,是为了缩小扫描范围而存在的一种机制。
根据SQL语句扫描:select * from t_user where name = 'jack',扫描name查找。
如果name字段上没有添加索引(目录),或者说没有给name字段创建索引,MySQL会进行全扫描,会将name字段上的每一个值都比对一遍。效率比较低。
MySQL在查询方面主要就是两种方式:
第一种方式:全表扫描。
第二种方式:根据索引检索。
在mysql数据库当中,索引也是需要排序的,并且这个索引的排序和TreeSet数据结构相同。TreeSet底层是一个自平衡的二叉树!在mysql当中索引是一个B-Tree数据结构。
遵循左小右大原则存放,采用中序遍历方式遍历取数据。
什么情况下,我们会考虑给字段添加索引呢?
1.数据量庞大(到底有多么庞大算庞大,这个需要测试,因为每一个硬件环境不同)。
2.该字段经常出现在where的后面,以条件的形式存在,也就是说这个字段总是被扫描。
3.该字段很少的DML操作,因为DML之后,索引需要重新排序。
建议不要随意添加索引,因为索引也是需要维护的,太多的话反而会降低系统的性能。建议通过主键查询,建议通过unique约束的字段进行查询,效率会比较高。
创建索引:
create index emp_ename_index on emp(ename);
给emp表的ename字段添加索引,起别名:emp_ename_index
删除索引:
drop index emp_ename_index on emp;
将emp表上的emp_ename_index索引对象删除。
在mysql当中,查看一个SQL语句是否使用了索引进行检索:
explain select * from emp where ename = 'KING';
索引也有失效的情况,如下:
"%"开头的模糊查询
select * from emp where ename like '%T';
尽量避免模糊查询的时候以"%"开头,这是一种优化的策略。
可以用SQL语句查看:explain select * from emp where ename like '%T';
使用or
如果使用or,那么要求or两边的条件字段都要有索引,索引才生效。如果其中一个字段没有索引,那么另一个字段上的索引也会失效。所以不建议使用or,可以使用union来代替。
使用复合索引
使用复合索引的时候,要使用左侧的列查找,索引才生效。使用右侧,则失效。
复合索引:两个字段,或者更多的字段联合起来添加一个索引。
create index emp_job_sal_index on emp(job,sal);
使用左侧:explain select * from emp where job = 'MANAGER'; 生效
使用右侧:explain select * from emp where sal= 800; 失效
索引列参与运算
在where当中索引列参加了运算,索引失效。
explain select * from emp where sal+1 = 800;
索引列使用了函数
在where当中索引列使用了函数。
explain select * from emp where lower(ename) = 'smith';
还有其他情况,先了解这些…
索引是各种数据库进行优化的重要手段,优化的时候优先考虑的因素就是索引。
索引在数据库当中分了很多类:
例:需要在examination_info表创建以下索引,规则如下:
在duration列创建普通索引 idx_duration、在exam_id列创建唯一性索引 uniq_idx_exam_id、在tag列创建全文索引 full_idx_tag。
create index idx_duration on examination_info(duration);
create unique index uniq_idx_exam_id on examination_info(exam_id);
create fulltext index full_idx_tag on examination_info(tag);
数据库设计范式:数据库表的设计依据,教你怎么进行数据库表的设计。
第一范式:要求任何一张表必须有主键,每一个字段原子性不可再分。
第二范式:建立在第一范式的基础上,要求所有非主键字段完全依赖主键,不要产生部分依赖。
第三范式:建立在第二范式的基础上,要求所有非主键字段直接依赖主键,不要产生传递依赖。
三范式是面试官经常问的,一定要熟记于心!!!
设计数据表的时候,按照以上的范式进行,可以避免表中数据的冗余,空间的浪费。
总结数据库表的设计:
一对一,第二张表外键唯一(fk+unique)
一对多,两张表,多的表加外键!
多对多,三张表,关系表两个外键!
嘱咐:
数据库设计三范式是理论上的,实践和理论有的时候有偏差。
最终的目的都是为了满足客户的需求,有的时候会拿冗余换执行速度。
因为在SQL中,表和表之间连接次数越多,效率越低。(笛卡尔积)
有的时候可能会存在冗余,但是为了减少表的连接次数,这样做也是合理的,并且对于开发人员来说,SQL语句的编写难度也会降低。