记录我的java之路——day22(周更)

day4-mysql高级

  • 索引

  • 视图

  • 事务

  • 存储过程

  • 函数

  • 数据库优化

索引(index)

​ 当表中有大量记录时,若要对表进行查询,第一种搜索信息方式是全表搜索,是将所有记录一一取出,和查询条件进行一一对比,然后返回满足条件的记录,这样做会消耗大量数据库系统时间,并造成大量磁盘I/O操作;第二种就是在表中建立索引,然后在索引中找到符合查询条件的索引值,最后通过保存在索引中的ROWID(相当于页码)快速找到表中对应的记录。

​ 索引提供指向存储在表的指定列中的数据值的指针,然后根据您指定的排序顺序对这些指针排序。数据库使用索引以找到特定值,然后顺指针找到包含该值的行。这样可以使对应于表的SQL语句执行得更快,可快速访问数据库表中的特定信息。

​ 索引类似字典的目录,可通过索引快速查询到目标数据。

索引分类

  1. 普通索引:MySQL中基本索引类型,没有什么限制,允许在定义索引的列中插入重复值和空值,纯粹为了查询数据更快一点

  2. 唯一性索引:索引列中的值必须是唯一的,但是允许为空值

  3. 主键索引:即表中主键列

  4. 全文索引:全文索引,只有在MyISAM引擎上才能使用,只能在CHAR,VARCHAR,TEXT类型字段上使用全文索引。

  5. 组合索引:在表中的多个字段组合上创建的索引,只有在查询条件中使用了这些字段的左边字段时,索引才会被使用,使用组合索引时遵循最左前缀集合。

索引相关命令

操作指令 代码
创建索引1 CREATE INDEX 索引名 ON 表名(列1[,列2...]);
创建索引2 ALTER TABLE 表明 ADD INDEX 索引名(列1[,列2...])
创建索引3 CREATE TABLE 表名 (列定义...., INDEX 索引名(列1[,列2...]));
创建唯一索引(索引列必须唯一) CREATE UNIQUE INDEX 索引名 ON 表名(列1[,列2...])
删除索引 DROP INDEX 索引名 ON 表名

案例:

-- 索引创建语法(普通单列索引)
create index ind_ename on emp(ename);
alter table emp add index ind_ename(ename);
​
-- 建立唯一索引
-- 普通索引
create table stu
(
id int primary key auto_increment,
sno varchar(30),
sname varchar(30),
unique key uq_sno(sno),
index ind_name(sname)   
)
​
-- 删除索引
drop index ind_ename on emp;
​
-- 组合索引
create index ind_name_job on emp(ename,job)
​
-- 以上组合索引等于建立两个索引 ename;ename,job

索引的优点:

  1. 大大加快数据的检索速度;

  2. 创建唯一性索引,保证数据库表中每一行数据的唯一性;

  3. 加速表和表之间的连接

  4. 在使用分组和排序子句进行数据检索时,可以显著减少查询中分组和排序的时间。

索引的缺点:

  1. 占用内存空间;

  2. 针对大表创建耗时较长;

  3. 当数据表中进行更新(insert,delete,update)操作时,索引也需要更新(耗时);

索引建立的原则:

  1. 不允许建立在重复率较高的字段上(性别列,职位列等);

  2. 对数据量较大的表建立

  3. 索引不要建立在经常更新的字段上

 

视图(view)

​ 视图(View)是从一个或多个表(或其他视图)导出的表,视图与表(Base Table)不同,视图是一个虚表,即视图所对应的数据不进行实际存储,数据库中只存储视图的定义,在对视图的数据进行操作时,系统根据视图的定义去操作与视图相关联的基本表。

​ 视图的定义存在数据库中,与此定义相关的数据并没有再存一份于数据库中。通过视图看到的数据存放在基表中。

​ 视图看上去非常像数据库的物理表,对它的操作同任何其它的表一样。当通过视图修改数据时,实际上是在改变基表中的数据;相反地,基表(base table)数据的改变也会自动反映在由基表产生的视图中。由于逻辑上的原因,有些视图可以修改对应的基表,而有些则不能(仅仅能查询)。

视图相关命令

操作指令 代码
创建视图 CREATE VIEW 视图名(列1,列2...) AS SELECT (列1,列2...) FROM ...;
查看视图 SELECT 列1,列2... FROM 视图名
修改视图 CREATE OR REPLACE VIEW 视图名 AS SELECT [列1,列2...] FROM [表1,表2...];
显示已有视图 SHOW TABLES [like...];(可以使用模糊查找)
查看视图详情 DESC 视图名或者SHOW FIELDS FROM 视图名
视图条件限制 [WITH CHECK OPTION](对没有where条件的视图无效)

案例:

-- 创建视图
create view v$emp as select name,addr,birth from employee;
-- 查看视图的数据
select * from v$emp;
select * from v$emp2;
​
-- 创建一个视图里面要求能够显示:
-- 员工的工号,姓名,地址,生日,所在部门名,以及月收入
create or replace view v$emp_info as 
select e.num,e.name,e.addr,e.birth,d.depname,s.income
from employee e,department d,salary s 
where e.num=s.num and e.depno=d.depno and s.income>2000
with check option;
​
select * from v$emp_info;
create view v$$emp as select name,depname,income from v$emp_info
​
update v$emp_info set income=1900 where num=3;
update v$emp_info set depname='市场部' where num=2;
​
-- 删除视图
drop view v$emp;

视图的作用

  1. 简化复杂的sql操作,编写sql查询后重用便捷而无需关注查询细节

  2. 对重构数据库提供逻辑独立保护数据,仅部分显示数据

  3. 保障机密数据安全

  4. 让数据展示更加精简,清晰

视图注意事项

  1. 视图名与表名一样必须唯一

  2. 创建视图的必须有足够权限,权限由数据库管理员授予

  3. 视图可以嵌套,即可以从其他视图中检索数据创建新的视图

  4. 不能在视图上建立索引,也不能关联触发器

  5. 视图可以和物理表共同使用

 

事务(transaction)

​ 数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。一个逻辑工作单元要成为事务,必须满足ACID(原子性、一致性、隔离性和持久性)原则。事务是数据库运行中的逻辑工作单位,由DBMS中的事务管理子系统负责事务的处理。

​ MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说,在电商系统中,产生一个订单时,我们既需要在订单表中新增一条记录,同时也要修改商品表中的库存量,并且需要保证这两次更新操作要么同时成功,要么同时失败,这样,这些数据库操作语句集就构成一个事务!MySQL数据库只有InnoDB引擎(MyISAM不支持事务)才支持事务。

ACID

原子性(Atomicity)

​ 事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。通常,与某个事务关联的操作具有共同的目标,并且是相互依赖的。如果系统只执行这些操作的一个子集,则可能会破坏事务的总体目标。原子性消除了系统处理操作子集的可能性。

一致性(Consistency)

​ 事务在完成时,必须使所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。事务结束时,所有的内部数据结构(如 B 树索引或双向链表)都必须是正确的。某些维护一致性的责任由应用程序开发人员承担,他们必须确保应用程序已强制所有已知的完整性约束。例如,当开发用于转帐的应用程序时,应避免在转帐过程中任意移动小数点。

隔离性(Isolation)

​ 由并发事务所作的修改必须与任何其它并发事务所作的修改隔离。事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。这称为隔离性,因为它能够重新装载起始数据,并且重播一系列事务,以使数据结束时的状态与原始事务执行的状态相同。当事务可序列化时将获得最高的隔离级别。在此级别上,从一组可并行执行的事务获得的结果与通过连续运行每个事务所获得的结果相同。由于高度隔离会限制可并行执行的事务数,所以一些应用程序降低隔离级别以换取更大的吞吐量。

持久性(Durability)

​ 事务完成之后,它对于系统的影响是永久性的。该修改即使出现致命的系统故障也将一直保持。

mysql查看和修改数据库引擎

操作指令 代码
显示当前引擎 SHOW ENGINES;
修改当前引擎(临时) SET DEFAULT_STORAGE_ENGINE=InnoDB|MyISAM
显示指定表的存储引擎 SHOW TABLE STATUS WHERE NAME='tbgoods'
创建表时指定引擎 CREATE TABLE 表名称(字段信息) ENGINE=InnoDB
设置指定表的存储引擎 ALTER TABLE 表名称 ENGINE = InnoDB;

事务相关指令

操作指令 代码
开启事务 BEGIN或START TRANSACTION
设置保存点 SAVEPOINT 保存点名称
释放保存点(删除) RELEASE SAVEPOINT 保存点名称;
提交事务 COMMIT
事务回滚 ROLLBACK
回滚到指定保存点 ROLLBACK TO 保存点名称
设置事务自动提交模式 SET AUTOCOMMIT=0 (0:禁止自动提交;1:开启自动提交)

存储过程(proceudre)

​ 存储过程(Procedure),是数据库操作语言SQL的可编程性实现,传统的SQL语句通常是在数据库服务器中执行一条命令,命令在数据库引擎内部需要经过创建与分析的过程,因此在运行时间上开销较大;而存储过程是预编译的,在首次运行一个存储过程时,查询优化器对其进行分析、优化,并给出最终被存在系统表中的存储计划,这样,后期的使用只需通过命令调用即可,因此,在执行过程时便可节省此开销。

  • 存储过程优点

    • 提高性能

    • 降低网络开销

    • 分担应用程序需要执行的业务逻辑(如:订单生成,通用分页等)

    • 更强的安全性

    • 比sql语句更为强大的处理能力

  • 存储过程缺点

    • 可移植性差(不同数据库服务器存储过程语法差异较大,一旦变更DBMS,则存储过程需要整体重构)

    • 逻辑复杂,不如sql灵活

    • 实际应用相对较少

存储过程创建语法

在命令行中编写存储过程时可通过DELIMITER修改默认结束标记(推荐图形界面工具)

DELIMITER $$ (使用“$$”符号作为结束标记,符号可自定义)

创建存储过程:

CREATE PROCEDURE 过程名([[IN |OUT |INOUT ]参数名1 类型1,参数名2 类型2...])

BEGIN

[DECLARE] 临时变量

-- 执行体

END

调用存储过程:

CALL 存储过程名();

删除存储过程:

DROP PROCEDURE 存储过程名;

相关实例:

存储过程:helloworld

-- 创建
create procedure sp_hello(msg varchar(30))
begin
    select concat('say:',msg);
end;
​
--调用
call sp_hello('你好');

综合案例(通用存储过程分页)

--创建
create PROCEDURE sp_comm_paging
(
tname varchar(100),
pagenow int,
pagesize int,
selection varchar(1000),
conditions varchar(1000),
sortcolumn varchar(100),
sorttype varchar(100),
out numcount int,
out pagecount int
)
BEGIN
    --定义变量表示查询起始位置
    DECLARE startnum int;
    if selection is null or selection = '' then
        set selection = '*';
    end if;
    if conditions is null or conditions = '' then
        set conditions = '1=1';
    end if;
    if sortcolumn is null or sortcolumn = '' THEN
        -- 要求每张表中必须有一个id字段
        set sortcolumn = 'id';
    end if;
    if sorttype is null or sortcolumn = '' THEN
        set sorttype = 'asc';
    end if;
    set @vsql = concat('select count(*) into @totalnum from ',tname,' where ',conditions);
    PREPARE stmt from @vsql;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
    -- 获取总记录数设置给输出参数
    set numcount = @totalnum;
    -- 避免无限上一页
    if pagenow < 1 THEN
        set pagenow = 1;
    end if;
    -- 计算获取总页数给输出参数
    set pagecount = ceiling(numcount/pagesize);
    -- 避免无限下一页
    if pagenow > pagecount THEN
        set pagenow = pagecount;
    end if;
    -- 计算获取查询的起始位置
    set startnum = (pagenow - 1) * pagesize;
    set @vsql = concat('select ',selection,' from ',tname,' where ',conditions, ' order by ',sortcolumn,' ',sorttype,' limit ',startnum,',',pagesize);
    PREPARE stmt from @vsql;
    execute stmt;
    DEALLOCATE PREPARE stmt;
END
​
--调用
call sp_comm_paging('employee',1,8,'name,addr,zip,tel,birth','addr like \'%大%\'','birth','asc',@countnum,@pgcount);
select @countnum,@pgcount;

 

函数(function)

函数有着跟存储过程类似的实现原理,但是两者之间也存在本质区别,具体如下:

  1. 一般来说,存储过程实现的功能要复杂一点,而函数的实现的功能针对性比较强。存储过程,功能强大,可以执行包括修改表等一系列数据库操作;用户定义函数不能用于执行一组修改全局数据库状态的操作。

  2. 对于存储过程来说可以返回参数,如记录集,而函数只能返回值或者表对象。函数只能返回一个变量;而存储过程可以返回多个。存储过程的参数可以有IN,OUT,INOUT三种类型,而函数只能有IN类,存储过程声明时不需要返回类型,而函数声明时需要描述返回类型,且函数体中必须包含一个有效的RETURNS语句。

  3. 存储过程,可以使用非确定函数,不允许在用户定义函数主体中内置非确定函数。

  4. 存储过程一般是作为一个独立的部分来执行( EXECUTE 语句执行),而函数可以作为查询语句的一个部分来调用(SELECT调用),由于函数可以返回一个表对象,因此它可以在查询语句中位于FROM关键字的后面。 SQL语句中不可用存储过程,而可以使用函数。

MySQL函数分为以下两类:

  • 预定义函数

  • 自定义函数

其中预定义函数为mysql内置函数主要包含以下:

  • 字符串函数

  • 数值函数

  • 日期函数

  • 系统信息函数

  • 加密函数

  • 格式化函数

自定义函数相关语法:

创建函数:

CREATE FUNCTION 函数名(参数列表)RETURNS 返回值类型BEGIN [DECLARE] 临时变量 -- 执行体 RETURN 返回值; END;

 

调用函数:

select 函数名(实参);

删除函数:

DROP FUNCTION 函数名;

实例:

-- 函数创建
create function fun_add(a int,b int)
returns INT
BEGIN
    DECLARE c int;
    set c = a + b;
    return c;
end
​
--函数调用
select fun_add(10,5);

数据库优化

一、SQL语句优化 (1)使用limit对查询结果的记录进行限定(2)避免select *,将需要查找的字段列出来(3)使用连接(join)来代替子查询(4)拆分大的delete或insert语句

二、选择合适的数据类型(1)使用可存下数据的最小的数据类型,整型 、< date,time < char,varchar < blob(2)使用简单的数据类型,整型处理比字符开销更小,因为字符串的比较更复杂。如:int类型存储时间类型(3)使用合理的字段属性长度,固定长度的表会更快。使用enum、char而不是varchar(4)尽可能使用not null定义字段(5)尽量少用text,非用不可最好分表

三、选择合适的索引列(1)查询频繁的列,在where,group by,order by,on从句中出现的列(2)where条件中<,<=,=,>,>=,between,in,以及like 字符串+通配符(%)出现的列(3)长度小的列,索引字段越小越好,因为数据库的存储单位是页,一页中能存下的数据越多越好(4)离散度大(不同的值多)的列,放在联合索引前面。查看离散度,通过统计不同的列值来实现,count越大,离散程度越高

四、分区分表

五、配置优化

作业

  1. 完成一个通用存储过程分页,提供任意的表名称,查询列,查询条件并且指定排序列,要求显示出符合以上条件的页码数据,并返回总数据条数以及总页码数

输入参数:

  • 当前页(必填)

  • 每页大小(必填)

  • 表名称(必填项)

  • 查询列(可选,默认为*)

  • 查询条件(可选)

  • 排序列(可选)

  • 排序方式(升序,降序)

输出参数:

  • 总记录行数

  • 总页码数

最终显示符合条件页码中的数据

2.利用存储过程(或函数)实现一个图书管理系统的图书借阅与还书功能

3.使用JDBC完成单表的CRUD操作

 

 

你可能感兴趣的:(记录我的java之路——day22(周更))