【MySql】MySql高级

视图

什么是视图

视图是基于查询的虚拟表。通俗的理解,视图就是一条 SELECT 语句执行后返回的结果集。

SELECT 语句所查询的表称为视图的基表,而查询的结果集称为虚拟表,视图本身并不存储具体的数据,视图的数据存在于视图的基表中,基本表数据发生了改变,视图的数据也会跟着改变。

使用视图是为了方便复杂的查询语句。基本思路是将复杂的查询语句定义在视图内部,然后对视图进行查询,从而简化复杂的查询语句。

定义视图

CREATE VIEW   视图名 AS SELECT 列 1,列 2... FROM 表(查询语句);

使用视图

SELECT * FROM 视图名

删除视图

drop view 视图名

存储过程

概述

如果实现用户的某些需求时,需要编写一组复杂的 SQL 语句才能实现,那么可以将这组复杂的 SQL 语句集编写在数据库中,由 JDBC 调用来执行这组 SQL语句。把编写在数据库中的 SQL 语句集称为存储过程。

存储过程(PROCEDURE)是事先经过编译并存储在数据库中的一段 SQL 语句的集合。调用存储过程可以简化应用开发人员的很多工作,减少数据在数据库和应用服务器之间的传输,对于提高数据处理的效率是有好处的。

存储过程类似于 JAVA 语言中的方法,需要先定义,使用时需要调用。存储过程可以定义参数,参数分为 IN、OUT、INOUT 类型三种类型。IN 类型的参数表示接收调用者传入的数据,OUT 类型的参数表示向调用者返回数据,INOUT类型的参数既可以接收调用者传入的参数,也可以向调用者返回数据。

MySQL 存储过程的定义

创建存储过程的语法格式

create procedure 存储过程名([in 变量名 类型,out 参数 2,…])

begin

[declare 变量名 类型 [DEFAULT 值];]

存储过程语句块;

end;

语法解析:

1.存储过程的参数分为 in,out,inout 三种类型。

2.in 代表输入参数(默认情况下为 in 参数),表示该参数的值必须由调用程序指定。

3.out 代表输出参数,表示该参数的值经存储过程计算后,将 out 参数的计算结果返回给调用程序。

4.inout 代表即是输入参数,又是输出参数,表示该参数的值即可以由调用程序指定,又可以将 inout 参数的计算结果返回给调用程序。

5.存储过程中的语句必须包含在 begin 和 end 之间。

6.declare 中用来声明变量,变量默认赋值使用 default,语句块中改变变量值,使用 set 变量=值;

存储过程使用

定义第一个存储过程

定义一个有参数的存储过程

流程控制语句

case when

循环

使用存储过程插入信息

函数

函数语法

create function 函数名([参数列表]) returns 数据类型

begin

DECLARE 变量;

sql 语句;

return 值;

end;

注意:

1.参数列表包含两部分:参数名 参数类型

2.函数体:肯定会有 return 语句,如果没有会报错

3.函数体中仅有一句话,则可以省略 begin end

4.使用 delimter 语句设置结束标记

设置函数可以没有参数

SET GLOBAL log_bin_trust_function_creators=TRUE;

删除函数

DROP FUNCTION 函数名;

带参数

触发器

触发器(trigger)是一种特殊的存储过程,其特殊性在于它并不需要用户直接 调用,而是在对表添加、修改、删除之前或者之后自动执行的存储过程。

触发器具有以下特点:

1.与表相关联

触发器定义在特定的表上,这个表称为触发器表。

2.自动激活触发器

当对表中的数据执行 INSERT、UPDATE 或 DELETE 操作时,如果对表上的这 个特定操作定义了触发器,该触发器自动执行,这是不可撤销的。

3.不能直接调用

与存储过程不同,触发器不能被直接调用,也不能传递或接受参数。

4.作为事务的一部分

触发器与激活触发器的语句一起做为对一个单一的事务来对待,可以从触发器中的任何位置回滚。

定义触发器的语法规则:

CREATE TRIGGER 触发器名称 触发时机 触发事件

ON 表名称

FOR EACH ROW -- 行级触发

BEGIN

语句

END;

语法解析:

1.触发器名称:是用来标识触发器的,由用户自定义。

2.触发时机:其值是 before 或 after。

3.触发事件:其值是 insert,update 和 delete

4.表名称:标识建立触发器的表名,即在哪张表上建立触发器

5.语句:是触发器程序体,触发器程序可以使用 begin 和 end 作为开始和结束,中间包含多条语句;

案例删除用户时,自动触发删除用户菜单关系

在行级触发器代码中,可以使用 old 和 new 访问到该行的旧数据和新数据,old和 new 是对应表的行记录类型变量。

MySQL 架构

进入到 mysql 高级内容学习之前,先整体认识一下 MySQL 的完整架构图.

连接层

最上层是一些客户端和连接服务,包含本地 sock 通信和大多数基于客户端 /服务端工具实现的类似于 tcp/ip 的通信。主要完成一些类似于连接处理、授权认证、及相关的安全方案。

服务层

第二层架构主要完成大多数的核心服务功能,如 SQL 接口,并完成缓存的查询,SQL 的分析和优化及部分内置函数的执行。所有跨存储引擎的功能也在这一层实现,如过程、函数等。在该层,服务器会解析查询并创建相应的内部解析树,并对其完成相应的优化,如确定查询表的顺序,是否利用素引等,最后生成相应的执行操作。如果是 select 语句,服务器还会查询内部的缓存。如果缓存空间足够大,这样在解决大量读操作的环境中能够很好的提升系统的性能。

引擎层

存储引擎层,存储引擎真正的负责了 MysQL 中数据的存储和提取,服务器通过 API 与存储引擎进行通信。不同的存储引擎具有的功能不同,这样我们可以根据自己的实际需要进行选取。

物理文件存储层

数据存储层,主要是将数据存储在运行于裸设备的文件系统之上,并完成与存储引擎的交互。

MySQL 引擎

概述

MySQL 中的数据用各种不同的技术存储在文件中。这些技术中的每一种 技术都使用不同的存储机制、索引技巧、锁定水平、并且最终提供广泛的不同的 功能和能力。通过选择不同的技术,你能够获得额外的速度或者功能,从而改善 你的应用的整体功能。

这些不同的技术以及配套的相关功能在 MySQL 中被称作存储引擎(也称作 表类型)。MySQL 默认配置了许多不同的存储引擎,可以预先设置或者在 MySQL 服务器中启用。你可以选择适用于服务器、数据库和表格的存储引擎,以便在选择如何存储你的信息、如何检索这些信息以及你需要你的数据结合什么性能和功能的时候为你提供最大的灵活性。

数据库引擎是用于存储、处理和保护数据的核心服务。利用数据库引擎可控制访问权限并快速处理事务,从而满足企业内大多数需要处理大量数据的应用程序的要求。

查看支持的引擎

SHOW ENGINES;

查看表引擎

SHOW TABLE STATUS LIKE '表名'

修改引擎

方式 1:将 mysql.ini 中 default-storage-engine=InnoDB,重启服务.

方式 2:建表时指定 CREATE TABLE 表名(...)ENGINE=MYISAM;

方式 3:建表后修改 ALTER TABLE 表名 ENGINE = INNODB;

存储引擎主要有

1. MyIsam , 2. InnoDB, 3. Memory, 4. Blackhole, 5. CSV, 6. Performance_Schema, 7. Archive, 8. Federated , 9 Mrg_Myisam

我们主要分析使用 MyIsam 和 InnoDB。

InnoDB

InnoDB:默认的存储引擎 。

InnoDB 是一个事务型的存储引擎,有行级锁和外键约束,支持全文检索(全文索引),它的设计目标是处理大容量数据库系统,MySQL 运行时 Innodb 会在内存中建立缓冲池,用于缓冲数据和索引;支持主键自增.不存储表的总行数.

MyISAM

MyISAM 也是 MySQL 的引擎,但是它没有提供对数据库事务的支持,也不支持行级锁和外键,因此当 INSERT(插入)或 UPDATE(更新)数据时即写操作需要锁定整个表,效率便会低一些;支持全文检索;存储表的总行数.

索引

为什么要有索引呢?

假设有一张表,表中有 100 万条数据,这 100 万条数据在硬盘上是存储在 数据页上的,一页数据大小为 16K,存储 100 万条数据需要很多数据页,假设其中有一条数据是 id='7900',如果要查询这条数据,其 SQL 是 SELECT * FROM 表名称 WHERE id = 7900。mysql 需要扫描全表来查找 id=7900 的记录。全表扫描就是从“数据页 1”开始,向后逐页查询。对于少量的数据,查询的速度会很快,但是,当随着数据量的增加,性能会急剧下降。100 万条数据逐页查询的时间是无法被用户接受的。

什么是索引

索引是帮助 MySQL 高效获取数据的数据结构

排好序的快速查找的数据结构.

数据库在存储数据本身之外,还维护着一个满足特定查找算法的数据结构,这些数据结构以某种方式指向数据,这样就可以在这些数据结构的基础上实现高级查找算法,这种数据结构就是索引。

左边是数据表,一共有两列七条记录,最左边的是数据记录的物理地址.

为了加快 Col2 的查找,可以维护一个右边所示的二叉查找树,每个节点分别包含索引键值和一个指向对应数据记录物理地址的指针,这样就可以运用二叉查找在一定的复杂度内获取到相应数据,从而快速的检索出符合条件的记录。

索引原理

索引的目的在于提高查询效率,与我们查阅图书所用的目录是一个道理:先定位到章,然后定位到该章下的一个小节,然后找到页数。相似的例子还有:查字典,查火车车次,飞机航班等.

本质都是:通过不断地缩小想要获取数据的范围来筛选出最终想要的结果,同时把随机的事件变成顺序的事件,也就是说,有了这种索引机制,我们可以总是用同一种查找方式来锁定数据。

索引类似于书的目录,在一本书前面加上目录,查找内容时不必逐页翻阅就能够快速地找到所需的内容。

借助索引,执行查询时不必扫描整个表就能够快速地找到所需要的数据。

索引优势

提高数据检索的效率,降低数据库的 IO 成本;

通过索引列对数据进行排序,降低数据排序的成本,降低了 CPU 的消耗;

索引劣势

实际上,索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录, 所以索引列也是要占用磁盘空间的。

虽然索引大大提高了查询速度,同时却会降低更新表的速度,例如对表进行INSERT,UPDATE 和 DELETE,因为更新表时,MySQL 不仅要保存数据,还要保存一下索引文件,每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息。

索引分类

主键索引:设定为主键后数据库会自动建立索引

ALTER TABLE 表名 add PRIMARY KEY 表名(列名);

删除建主键索引:

ALTER TABLE 表名 drop PRIMARY KEY ;

单值索引:即一个索引只包含单个列,一个表可以有多个单列索引

创建单值索引

CREATE INDEX 索引名 ON 表名(列名);

删除索引:

DROP INDEX 索引名;

唯一索引:索引列的值必须唯一,允许为 null

CREATE UNIQUE INDEX 索引名 ON 表名(列名);

删除索引

DROP INDEX 索引名 ON 表名;

组合索引(复合索引):

即一个索引包含多个列,在数据库操作期间,复合索引比单值索引所需要的开销更小(对于相同的多个列建索引),当表的行数远大于索引列的数目时可以使用复合索引.

创建复合索引

CREATE INDEX 索引名 ON 表名(列 1,列 2...);

删除索引:

DROP INDEX 索引名 ON 表名;

组合索引最左前缀原则

列如表中有 a,b,c 3 列,为 a,b 两列创建组合索引,那么在使用时需要满足最左侧索引原则.在使用组合索引的列作为条件时,必须要出现最左侧列为条件,否则组合索引不生效.

列如 select * from table where a=’’and b=’’索引生效

   select * from table where b=’’and a=’’索引生效

   select * from table where a=’’and c=’’索引生效

   select * from table where b=’’and c=’’索引不生效

全文索引

需要模糊查询时,一般索引无效,这时候就可以使用全文索引了。

CREATE FULLTEXT INDEX 索引名 ON 表名(字段名) WITH PARSER ngram;

SELECT 结果 FROM 表名 WHERE MATCH(列名) AGAINST(‘搜索词')

查看索引:

SHOW INDEX FROM 表名;

索引创建原则

哪些情况需要创建索引

主键自动建立唯一索引 ;

频繁作为查询条件的字段应该创建索引(where 后面的语句) ;

查询中与其它表关联的字段,外键关系建立索引 ;

查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度 ;

分组中的字段 ;

哪些情况不要创建索引

表记录太少 ;

经常增删改的表:提高了查询速度,同时却会降低更新表的速度,如对表进 行 INSERT、UPDATE 和 DELETE,因为更新表时,MySQL 不仅要保存数据, 还要保存一下索引文件;

Where 条件里用不到的字段不创建索引 ;

数据重复且分布平均的表字段,因此应该只为最经常查询和最经常排序的数据列建立索引,某个数据列包含许多重复的内容,建立索引没有太大实际效果。

索引数据结构

B+树之前必须先了解二叉查找树、平衡二叉树(AVLTree)和平衡多路查找树(B-Tree),B+树即由这些树逐步优化而来。使其更适合实现外存储索引结构,InnoDB 存储引擎就是用 B+Tree 实现其索引结构。

排好序的,一个节点可以存储多个数据.

非叶子节点不存储数据,只存储索引,可以放更多的索引.

数据记录都存放在叶子节点中.

所有叶子节点之间都有一个链指针.

Mysql 索引使用的是 B+树,因为索引是用来加快查询的,而 B+树通过对数据进行排序所以是可以提高查询速度的,然后通过一个节点中可以存储多个元素,从而可以使得 B+树的高度不会太高.并且叶子节点之间有指针,可以很好的支持全表扫描,范围查找等 SQL 语句。

聚簇索引和非聚簇索引

聚簇索引

找到了索引就找到了需要的数据,那么这个索引就是聚簇索引,所以主键就是聚簇索引。

非聚簇索引

索引的存储和数据的存储是分离的,也就是说找到了索引但没找到数据,需要根据索引上的值(主键)再次回表查询,非聚簇索引也叫做辅助索引。

一个例子

下面我们创建了一个学生表,做三种查询,来说明什么情况下是聚簇索引,什么情况下不是。

第一种,直接根据主键查询获取所有字段数据,此时主键是聚簇索引,因为主键对应的索引叶子节点存储了 id=1 的所有字段的值。

SELECT * FROM student WHERE id = 1

第二种,根据编号查询编号和名称,编号本身是一个唯一索引,但查询的列包含了学生编号和学生名称,当命中编号索引时,该索引的节点的数据存储的是主键 ID,需要根据主键 ID 重新查询一次,所以这种查询下 no 不是聚簇索引 。

SELECT NO,NAME FROM student WHERE NO = 123

第三种,我们根据编号查询编号(有人会问知道编号了还要查询?要,你可能需要验证该编号在数据库中是否存在),这种查询命中编号索引时,直接返回编号,因为所需要的数据就是该索引,不需要回表查询,这种场景下 no 是聚簇索引。

SELECT NO FROM student WHERE NO = 123

MySQL 中 InnoDB 引擎的索引和文件是存放在一起的,找到索引就可以找到数据,是聚簇式设计.

而 MyISAM 引擎采用的是非聚簇式设计,索引文件和数据文件不在同一个文件中。

事务

事务的概述

事务是数据库为了保证数据操作的原子性、隔离性、持久性、一致性(事务的四个特征),数据库提供了一套机制,在同一个事务中,如果有多条的sql执行,事务要确保执行的可靠性。

在MySql中只有使用了Innodb数据库引擎的数据库才支持事务。

事务特性

事务满足ACID特性;

原子性:一个事务中的所有操作,要么全部完成,要么全部不完成,执行过程中发生错误,就会回滚,回到没执行事务前一样;

持久性:一旦提交事务,事务处理结束后,对数据的修改就是永久的,即便故障也不会丢失,永远保存在硬盘上;

隔离性:因为数据库允许多个并发事务对同事对其数据库进行读写和修改的能力,所以当有多个事务同事对数据进行操作,需要不同的隔离机制,进行数据控制,防止数据不完整;

一致性:数据经过很多次的操作,最终结果要与预期的一样,保证数据的完整性(不能出现转了100,对方收到50的情况)。

原子性、隔离性、持久性都是为了保证数据的一致性。

事务隔离级别

有四种隔离级别:

1.读未提交:B事务读到了A事务未提交的数据,产生脏读(B读到了

垃圾数据,A事务可能会回滚);

解决办法:设置隔离级别为读已提交。

2.读已提交:B事务读到了A事务已经提交的事务,解决了脏读问题,但会产生不可重复读的问题(B事务在开启两次查询中,两次查询结果不一样)。

3.可重复读:B事务在开启后的两次查询中,两次查询结果是相同的,解决了不可重复读的问题,但会产生幻读问题(一般的查询sql不会产生幻读,但例如执行Selec…for update 会出现幻读)。

4.串行化:加锁,只要有一个事务进行操作,其他事务就得等待,即使是一个读操作,也会锁定。串行化是最安全的隔离级别,可以解决以上所有问题,但速度也是最慢的。

MySql中默认的隔离级别为可重复读。

事务实现原理

原子性:原子性的实现依赖的日志文件是undo log(回滚日志)。里面保存的是每次操作的反向操作,如我们执行insert操作,那么日志文件中保存delete操作。当回滚时执行反向操作,把数据改回去。

持久性:每当执行修改操作时,先将语句保存到redo log(重做日志)中,即使突然断电,回复正常后也可以从日志中恢复数据。

隔离级别实现原理(MVCC)

多版本并发控制 Multi-Version Concurrent Control。

主要是针对读已提交和可重复读。

读已提交(当前读):只要别的事务提交了,那么另一个事务就可以看到。特点:有可能同一个事务的两次查询不一致,时时访问到的是最新的数据。注:读已提交也叫当前读,每次读时都会给版本链拍照,所以他读到的数据是最新的(已提交的数据)。

可重复读(快照读):B事务开始后,第一次读到数据,和之后读到的数据一致的,做个过程中别的事务已经修改过了。注:可重复读也叫快照读,第一次读的时候会把版本链拍照,下一次(同一个事务)读时,从版本快照中读,所以第一次和第二次读到的数据是一致的。

使用隔离级别机制,是为了实现并发的读-写、写-读操作,提高系统性能。

锁机制

MySql支持行锁、间隙锁、表锁。

行锁:只给操作的行加锁,如果两个事务操作的是同一行,那必须一个一个的执行。特点:开销大,加锁慢

间隙锁:一般指的是范围的一个区间,对某一个区间进行加锁,例如ID>5 and id<10。

表锁:对整个表加锁,Myisam默认支持表锁,innodb若要使用表锁需改配置。

共享锁(读锁):如果我们事务在读数据时,不想让其他事务写,还要让其他事务读,那么查询语句可以加共享锁。测试语句:select…locl in share mode。

排它锁(独占锁):写操作默认的是排它锁。当我们读数据时,要求数据足够准确,可以给读操作加排它锁,测试语句:select…for update。

SQL优化的一些方法

1.查询SQL尽量不要使用select*,而是具体字段

2.避免在where子句中使用or来连接

3.尽量使用数值代表字符串类型

4.使用varchar代替char类型

5.对查询进行优化,尽量避免全表扫描,首先应该考虑在where及order by涉及的列上建立索引

6.尽量避免索引失效

7.inner join、left join、reght join,优先使用inner join

8.提高group by语句的效率

9.清空表时优先使用truncate

truncate比delet删除效率高

delete在dml侧面,逐行删除

truncate在ddl层面,表结构进行删除

10.表连接不宜太多,索引不宜太多,一般5个以内

11.避免在索引列上使用内置函数

12.使用explian分析SQL执行计划

执行计划

EXPLAIN

使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,从而知道MySQL

是如何处理你的 SQL 语句的。分析你的查询语句或是表结构的性能瓶颈。

EXPLAIN的作用

表的读取顺序

数据读取操作的操作类型

表之间引用

哪些索引可以使用

哪些索引被实例引用

每张表有多少行被优化器查询

EXPLAIN的使用

在 select 语句之前增加 explain 关键字,执行查询会返回执行计划的信息, 而不是执行 SQL。

例如:EXPLAIN SELECT * FROM USER WHERE id = 1

测试期间设置关闭对衍生表的合并优化,不关闭时,mysql 对简单查询进行优化, 不显示。

SET SESSION optimizer_switch='derived_merge=off';

expain 出来的信息有 12 列,分别是:

id, select_type, table, type, possible_keys, key, key_len, ref, rows, Extra

概要描述

id:选择标识符

select_type:表示查询的类型。

table:输出结果集的表

partitions:匹配的分区

type:表示表的连接类型

possible_keys:表示查询时,可能使用的索引

key:表示实际使用的索引

key_len:索引字段的长度

ref:列与索引的比较

rows:扫描出的行数(估算的行数)

filtered:按表条件过滤的行百分比

Extra:执行情况的描述和说明

id

SELECT 识别符。这是 SELECT 的查询序列号 id 如果相同,可以认为是一组,从上往下顺序执行;

在所有组中,id 值越大,优先级越高,越先执行。

select_type

表示查询中每个 select 子句的类型

1.SIMPLE(简单 SELECT,不使用 UNION 或子查询等)

2.PRIMARY(子查询中最外层查询,查询中若包含任何复杂的子部分,最外层的select 被标记为 PRIMARY)

3.SUBQUERY(子查询中的第一个 SELECT,结果不依赖于外部查询)

4.DERIVED(派生表的 SELECT, FROM 子句的子查询)

5.UNION(UNION 中的第二个或后面的 SELECT 语句)

6.UNION RESULT(UNION 的结果,union 语句中第二个 select 开始后面所有select)

type

对表访问方式,表示 MySQL 在表中找到所需行的方式,又称“访问类型”。 常用的类型有:system>const>eq_ref>ref>range>index>ALL(从左到右, 性能从好到差).

system: 表只有一行记录(等于系统表),平时不会出现,这个也可以忽略不计.

const: 表示通过索引一次就找到了,const 用于比较 primary key 或者 unique索引。

eq_ref: 唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描.

ref: 非唯一性索引扫描,返回匹配某个单独值的所有行.本质上也是一种索引访 问,它返回所有匹某个单独值的行,然而,它可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体.

range: 只检索给定范围的行,使用一个索引来选择行。key 列显示使用了哪个索引一般就是在你的where 语句中出现了 between、<、>、in 等的查询这种范围扫描索引扫描比全表扫描要好,因为它只需要开始于索引的某一点,而结束语另一点,不用扫描全部索引。

index: Full Index Scan,index 与 ALL 区别为 index 类型只遍历索引树。这通常比 ALL 快,因为索引文件通常比数据文件小。也就是说虽然 all 和 Index 都是读全表,但 index 是从索引中读取的,而 all 是从硬盘中读的)

All: Full Table Scan,将遍历全表以找到匹配的行一般来说,得保证查询至少达到 range 级别,最好能达到 ref.

possible_keys

显示可能应用在这张表中的索引,一个或多个。 查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用key实际使用的索引。如果为 NULL,则没有使用索引,或者索引失效

ken_len

表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。在不损失精确性的情况下,长度越短越好.

ref

显示索引的哪一列被使用了,如果可能的话,是一个常数。哪些列或常量被用于查找索引列上的值

rows

根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数.

Extra

额外的信息说明

Using filesort:

当 Query 中包含 ORDER BY 操作,而且无法利用索引完成排序操作的时候,Mysql 无法利用索引完成排序的操作称为”文件排序”.

Using temporary:

使了用临时表保存中间结果,MySQL 在对查询结果排序时使用临时表。常见于排序 order by 和分组查询 group by。

Using index:

表示相应的 select 操作中使用了索引,避免访问了表的数据行,效率不错!

如果同时出现 using where,表明索引被用来执行索引键值的查找;如果没有同时出现 using where,表明索引用来读取数据而非执行查找动作。

Using where:

表示使用到了索引 , 但是也进行了 where 过滤

猜你喜欢

转载自blog.csdn.net/m0_56492261/article/details/129595172