一、存储程序
存储程序指的一组存储和执行在数据库服务器端的程序。存储程序总是在服务器的进程或者线程的内存中执行的。
(一)存储过程 create procedure sel_procedure([参数])
(A)定义:
类似于方法,有过程名称,参数列表,过程体组成。
过程创建,过程调用。
-- 声明
delimiter //
create PROCEDURE selEmpByNo(eno int)
begin
select ename from emp where empno = eno;
end;
//
-- 调用
call selEmpByNo(7788);
(B)参数有三种模式:
- IN:默认。 由外部将参数传入过程。
- OUT: 可以由存储过程将值传出。
- INOUT: 可以传入也可以传出。
(C)分支语句
#分支:
delimiter //
create procedure score_level(score int)
begin
-- 声明变量
declare v_level varchar(20);
if score >= 90 then
set v_level = 'A';
elseif score >=80 then
set v_level = 'B';
elseif score >= 70 then
set v_level = 'C';
else
set v_level = 'D';
end if;
select v_level;
end;
//
(D)循环
- While 条件 do … end while;
- Loop…….end loop; (leave)
- Repeat … end repeat; (until)
#循环:
While 条件 do … end while;
Loop…….end loop; (leave)
Repeat … end repeat; (until)
#while
delimiter //
create procedure calc1()
begin
declare i int;
declare sum int;
set i = 1;
set sum = 0;
while i<=100 do
set sum = sum + i;
set i = i+1;
end while;
select sum;
end;
//
call calc1();
#loop
delimiter //
create procedure calc2()
begin
declare i int;
declare sum int;
set i = 1;
set sum = 0;
lip:loop
set sum = sum + i;
set i = i+1;
if i>100 then
leave lip;
end if;
end loop;
select sum;
end;
//
call calc2();
#repeat
delimiter //
create procedure calc3()
begin
declare i int;
declare sum int;
set i = 1;
set sum = 0;
repeat
set sum = sum + i;
set i = i+1;
until i>100
end repeat;
select sum;
end;
//
call calc3();
(二)存储函数:有参数和返回值。 create function fun_sel([参数])
-- 存储函数(eno查询ename)
delimiter //
create function fun_sel(eno int)
returns varchar(20) -- 返回值的类型
DETERMINISTIC -- 确定
begin
declare v_name varchar(20);
select ename into v_name from emp where empno = eno;
return v_name;
end;
//
select fun_sel(7788);
存储过程和存储函数的区别:
- 1.关键字不同,存储过程为procedure,存储函数为function;
- 2.存储过程通过参数模式返回值,函数可以通过return返回值
- 3.存储过程可以作为独立调用的个体,函数必须作为sql的一部分进行调用。
三、触发器 create trigger trig_name
触发器不能手动调用也不能传递参数。由事件触发。Mysql里增删改会触发。
Mysql只支持行级触发器,Oracle支持表级触发器。
#语法格式:
CREATE
[DEFINER = { user | CURRENT_USER }]
TRIGGER trigger_name
trigger_time trigger_event
ON tbl_name FOR EACH ROW
[trigger_order]
trigger_body
trigger_time: { BEFORE | AFTER }
trigger_event: { INSERT | UPDATE | DELETE }
trigger_order: { FOLLOWS | PRECEDES } other_trigger_name
例子
delimiter //
create trigger tri_stu
after delete
on stu for each row
begin
insert into student(sname,cid) values(old.sname,old.cid);
end;
//
触发器影响性能。
二、视图和索引
(一)视图 create view view_name
(A)视图定义:是实体表的一个虚拟映射,在数据库中没有物理结构存在。
(B)视图
- 1.视图数据来自于基表,
- 2.视图可以使用增删改查的功能,视图增删改功能会修改基表数据。
- 所以视图创建是为了查找,不是为了增删改。
(C)基本语法
create view view_emp
as
select * from emp where deptno = 10 with check option;
select * from view_emp;
update view_emp set deptno = 20;
drop view view_emp;
(D)视图特点
- 1.简化开发。存储之前查找出来的集合。
- 2.安全性。只映射出一部分内容公开给别人看。
- 3.定制化数据。拆分或组合字段信息。
(二)索引 create index index_name on table(id)
索引是为提高查询效率设计的数据结构。本质需要文件存储,需要维护。
#创建索引
create index index_sid on stu(sid);
#销毁索引
drop index index_sid on stu;
(A)索引的添加规则
- 1.数据量较大
- 2.添加索引在高奇数时
- 3.不能添加过多索引(需要维护)
- 4.默认是B树索引
(B)不适合添加
- 增删改过多的操作。增删改操作不能超过5%。
三、数据库设计
(一)三大范式(减少冗余)
层层递进,一层比一层要求严格
1NF:数据的列都是不可分割的原子性。
如一个地址字段内容是:北京市昌平区立水桥路155号;
如果要查找昌平区的所有人,利用like或取子串,效率就很低。
应该将字段拆成 市字段,区字段,路字段。
不能再分。
2NF 所有的非主键信息必须与主键信息相关,如果有联合主键,应与联合主键完全相关,不能与部分主键相关。
(一张表只描述一个事物)
如:用户信息里就不能出现商品的信息。
3NF 所有非主键字段必须与主键直接相关,非主键字段之间不能直接相关。
(即非主键不能与主键传递相关)
- 有时为了提高查询效率,而违反三大范式。
(二)数据库设计
(A)设计步骤
1.需求分析
2.概念结构设计阶段
是整个数据库设计的关键。
设计数据库的E-R概念图,确认需求信息的正确和完整(Entity-Relationship)
(B)实体图设计
(a)图形
- 矩形:表示实体
- 菱形:表示联系
- 椭圆表示实体的属性
(b)实体之间的关系如何在数据库里体现
- #一对一关系:如个人信息表和档案表
- 1.约束方式一:外键添加唯一约束
- 2.约束方式二:主键作为外键
- #一对多:如部门和员工
- 约束方式:直接添加外键(简单)
- #多对多:学生表和课程表
- 约束方式:需要增加关系管理表,并且设计联合主键
- 两张表肯定解决不了问题。
一对一例子
---------------------------------------------------
person表
pk
pid pname sex
1 zs man
-------------------------------------------------
一对一设计方法一 :外键添加唯一约束
record表
pk fk外键 unique
rid rcontent rdate pid
1 zs's 1999-09-09 1
--------------------------------------------------
一对一设计方法二 :主键作为外键
record表
pk fk
rid rcontent rdate pid
1 zs's 1999-09-09 1
--------------------------------------------------
多对多例子
----------------------------------------------------
student 学生表
pk
sid sname
1 zs
2 ls
-----------------------------------------------------
course 课程表
pk
cid
1 java
2 c
----------------------------------------------------
stu-course
sid cid
1 1
2 1
2 2
1 2
---------------------------------------------------
(c)用PowerDesigner软件设计数据库
先new 概念模型,再设计实体类及其关系,然后tool->生成物理模型;然后DataBase->生成数据库。
1.设计好实体类
2.设计好实体类后,生成物理模型
3.生成数据库
四、SQL语言设计优化
(一)设计原则
(A)select语句尽量不用*
(B)用UNION替换OR(适用于索引列)
(C)用EXISTS替代IN、用NOT EXISTS替代NOT IN
(二)以下会导致索引失效
- ① Not Null/Null 如果某列建立索引,当进行Select * from emp where depto is not null/is null。 则会是索引失效。
- ② 索引列上不要使用函数,
- SELECT Col FROM tbl WHERE substr(name ,1 ,3 ) = ‘ABC’(不)
- SELECT Col FROM tbl WHERE name LIKE ‘%ABC%’ (不)
- SELECT Col FROM tbl WHERE name LIKE ‘ABC%’ (使用)。
- ③ 索引列上不能进行计算
- SELECT Col FROM tbl WHERE col / 10 > 10 则会使索引失效
- 应该改成SELECT Col FROM tbl WHERE col > 10 * 10
- ④ 索引列上不要使用NOT ( != 、 <> )
如:SELECT Col FROM tbl WHERE col ! = 10 应该
改成:union。
(三)用UNION替换OR(适用于索引列)
- union:是将两个查询的结果集进行追加在一起,它不会引起列的变化。
- 由于是追加操作,需要两个结果集的列数应该是相关的,并且相应列的数据类型也应该相当的。
- union 返回两个结果集,同时将两个结果集重复的项进行消除。 如果不进行消除,用UNOIN ALL.
- 通常情况下, 用UNION替换WHERE子句中的OR将会起到较好的效果. 对索引列使用OR将造成全表扫描.
- 注意, 以上规则只针对多个索引列有效.
- 如果有column没有被索引, 查询效率可能会因为你没有选择OR而降低.
(四)用EXISTS替代IN、用NOT EXISTS替代NOT IN
- 在许多基于基础表的查询中, 为了满足一个条件, 往往需要对另一个表进行联接. 在这种情况下, 使用EXISTS(或NOT EXISTS)通常将提高查询的效率.
- 在子查询中, NOT IN子句将执行一个内部的排序和合并. 无论在哪种情况下, NOT IN都是最低效的(因为它对子查询中的表执行了一个全表遍历).
- 为了避免使用NOT IN, 我们可以把它改写成外连接(Outer Joins)或NOT EXISTS.
- 高效: SELECT * FROM EMP (基础表) WHERE EXISTS (SELECT ‘X’ FROM DEPT WHERE DEPT.DEPTNO = EMP.DEPTNO AND LOC = ‘MELB’)
- 低效: SELECT * FROM EMP (基础表) WHERE DEPTNO IN(SELECT DEPTNO FROM DEPT WHERE LOC = ‘MELB’)
五、备份和还原
#备份
Mysqldump -uroot -proot dbname > d:/t.sql;
#还原
mysql -u root -p < C:\backup.sql