2021-01-01

## 一、两个引擎的对比

### MyISAM

- 不支持事务,但是整个操作是原子性的(事务具备四种特性:原子性、一致性、隔离性、持久性)

- 不支持外键,支持表锁,每次锁住的是整张表

MyISAM的表锁有读锁和写锁(<font color='red'>两个锁都是表级别</font>)

一个MyISAM表有三个文件:索引文件,表结构文件,数据文件

存储表的总行数,执行<font color='orange'>select count(*) from table</font>时只要简单的读出保存好的行数即可

采用非聚集索引,索引文件的数据域存储指向数据文件的指针。辅索引与主索引基本一致,但是辅索引不用保证唯一性。

<font color='red'>对于AUTO_INCREMENT类型的字段,在MyISAM表中,可以和其他字段一起建立联合索引。</font>

### InnoDB

- 支持事务,支持事务的四种隔离级别;是一种具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。

- 支持行锁和外键约束,因此可以支持写并发

- 不存储总行数;也就是说,执行select count(*) from table时,InnoDB要扫描一遍整个表来计算有多少行。注意的是,当count(*)语句包含 where条件时,两种表的操作是一样的。

- 对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引

- DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除

- 一个Innodb表存储在一个文件内(共享表空间,表大小不受操作系统的限制),也可能为多个(设置为独立表空间,表大小受操作系统限制,大小为2G),受操作系统文件大小的限制

- 主键索引采用聚集索引(索引的数据域存储数据文件本身),辅索引的数据域存储主键的值;因此从辅索引查找数据,需要先通过辅索引找到主键值,再访问主键索引;最好使用自增主键,防止插入数据时,为维持B+树结构,文件的大调整。

  ### 两者的区别

![img](12.11.assets/1266222-20181002095044128-1277628264.png)

## 二、MySQL磁盘碎片

### 碎片产生的原因

- <font color='orange'>表的存储会出现碎片化</font>,每当删除了一行内容,该段空间就会变为空白、被留空,而在一段时间内的大量删除操作,会使这种留空的空间变得比存储列表内容所使用的空间更大;

- 当执行插入操作时,MySQL会尝试使用空白空间,但如果某个空白空间一直没有被大小合适的数据占用,仍然无法将其彻底占用,就形成了碎片;

- 当MySQL对数据进行扫描时,它扫描的对象实际是列表的容量需求上限,也就是数据被写入的区域中处于峰值位置的部分

如:<font color='orange'>一个表有1万行,每行10字节,会占用10万字节存储空间,执行删除操作,只留一行,实际内容只剩下10字节,但MySQL在读取时,仍看做是10万字节的表进行处理,所以,碎片越多,就会越来越影响查询性能。</font>

#### 查看表碎片的大小:

```MySQL

show table status like '表名';

```

结果中'Data_free'列的值就是碎片大小

![img](12.11.assets/20171019111511165.png)

#### 列出所有已经产生碎片的表:

```MySQL

select table_schema db, table_name, data_free, engine from information_schema.tables where table_schema not in ('information_schema', 'mysql') and data_free > 0;

```

#### 清理表碎片

1. MyISAM表:

  ```MySQL

  optimize table 表名;

  ```

2. InnoDB表:

  ```MySQL

  alter table 表名 engine = InnoDB;

  ```

  ## 三、数据库优化

<font color='orange'>是否需要清理碎片、上的锁是否为表锁</font>

<font color='orange'>select后不要用*,不然会回表</font>

#### 选取最适用的字段属性

<font color='red'>数据库中的表越小,在它上面执行的查询也就会越快。</font>因此,在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度设得尽可能小

**另外一个提高效率的方法是在可能的情况下,应该尽量把字段设置为NOT NULL**,这样在将来执行查询的时候,数据库<font color='red'>不用去比较NULL值</font>

因为在MySQL中,ENUM类型被当作数值型数据来处理,而数值型数据被处理起来的速度要比文本类型快得多

#### 使用连接(JOIN)来代替子查询(Sub-Queries)

使用子查询可以一次性的完成很多逻辑上需要多个步骤才能完成的SQL操作,同时也可以<font color='red'>避免事务或者表锁死</font>,并且写起来也很容易。但是,有些情况下,<font color='red'>子查询可以被更有效率的连接(JOIN)替代</font>。

#### 使用联合(UNION)来代替手动创建的临时表(不懂)

可以把需要使用临时表的两条或更多的<font color='orange'>select</font>查询合并的一个查询中。在客户端的查询会话<font color='red'>结束的时候</font>,临时表会被<font color='red'>自动删除</font>,从而保证数据库整齐、高效

用union来创建查询的时候,我们只需要用UNION作为关键字把多个select语句连接起来就可以了,要注意的是所有select语句中的字段数目要想同。

#### 事务

事务原理是:<font color='red'>要么语句块中每条语句都操作成功,要么都失败</font>。换句话说,<font color='orange'>就是可以保持数据库中数据的一致性和完整性</font>。事物以<font color='orange'>BEGIN</font>关键字开始,<font color='orange'>COMMIT</font>关键字结束。在这之间的一条SQL操作失败,那么,<font color='orange'>rollback</font>命令就可以把数据库恢复到<font color='orange'>BEGIN</font>开始之前的状态。

<font color='cornflowerblue'>事务的另一个重要作用是当多个用户同时使用相同的数据源时,它可以利用锁定数据库的方法来为用户提供一种安全的访问方式,这样可以保证用户的操作不被其它的用户所干扰。</font>

#### 锁定表

尽管事务是维护数据库完整性的一个非常好的方法,但却因为它的<font color='red'>独占性</font>,有时会影响数据库的性能,尤其是在很大的应用系统中。<font color='red'>由于在事务执行的过程中,数据库将会被锁定</font>,因此其它的用户请求<font color='red'>只能暂时等待直到该事务结束</font>。如果一个数据库系统只有少数几个用户来使用,事务造成的影响不会成为一个太大的问题;但假设有成千上万的用户同时访问一个数据库系统,就会产生比较严重的响应延迟。此时通过<font color='red'>锁定表</font>的方法来获得更好的性能

#### 使用外键

锁定表的方法可以<font color='red'>维护数据的完整性</font>,但是它<font color='red'>却不能保证数据的关联性</font>。这个时候我们就可以使用<font color='orange'>外键</font>。

#### 使用索引

索引是提高数据库性能的常用方法,它可以令数据库服务器以比没有索引快得多的速度检索特定的行,尤其是在查询语句当中包含有<font color='red'>MAX()</font>,<font color='red'>MIN()</font>和<font color='red'>ORDERBY</font>这些命令的时候,性能提高更为明显。

一般说来,索引应建立在那些将用于<font color='red'>JOIN,WHERE</font>判断和<font color='red'>ORDER BY</font>排序的字段上。尽量不要对数据库中某个含有大量重复的值的字段建立索引。

#### 优化的查询语句

绝大多数情况下,使用索引可以提高查询的速度,但如果<font color='red'>SQL语句使用不恰当的话</font>,索引将无法发挥它应有的作用。

- 不能将一个建有索引的<font color='orange'>int</font>字段和<font color='orange'>bigint</font>字段进行比较;但是作为特殊的情况,在<font color='orange'>CHAR</font>类型的字段和<font color='orange'>VARCHAR</font>类型字段的字段大小相同的时候,可以将它们进行比较。

- 在建有索引的字段上尽量<font color='orange'>不要使用函数</font>进行操作

- 在搜索字符型字段时,我们有时会使用<font color='red'>LIKE关键字和通配符</font>,这种做法虽然简单,但却也是<font color='red'>以牺牲系统性能为代价</font>的。

## 四、慢查询日志

MySQL的慢查询日志是MySQL提供的一种日志记录,它用来记录在MySQL中响应时间超过阀值的语句,具体指运行时间超过<font color='orange'>long_query_time</font>(<font color='red'>long_query_time的默认值为10,意思是运行10S以上的语句</font>)值的SQL,则会被记录到慢查询日志中。

#### 慢查询日志相关参数

```MySQL

slow_query_log:是否开启慢查询日志,1表示开启,0表示关闭。

show variables like '%slow_query_log';

slow-query-log-file:MySQL数据库慢查询日志存储路径。可以不设置该参数,系统则会默认给一个缺省的文件host_name-slow.log

show variables like '%slow_query_log-file';

long_query_time :慢查询阈值,当查询时间多于设定的阈值时,记录日志。

show VARIABLES like 'long_query_time%';

log_queries_not_using_indexes:未使用索引的查询也被记录到慢查询日志中(可选项)。

show variables like '%log_queries_not_using_indexes';

```

<font color='red'>log_output</font>:日志存储方式。<font color='red'>log_output='FILE'</font>表示将<font color='orange'>日志存入文件,默认值是'FILE'。</font><font color='red'>log_output='TABLE'</font>表示将<font color='orange'>日志存入数据库</font>,这样日志信息就会被写入到<font color='orange'>mysql.slow_log表</font>中。MySQL数据库支持同时两种日志存储方式,配置的时候以逗号隔开即可,如:<font color='orange'>log_output='FILE,TABLE'。</font>日志记录到系统的专用日志表中,要比记录到文件耗费更多的系统资源,因此对于需要启用慢查询日志,又需要能够获得更高的系统性能,那么建议优先记录到文件。

```mysql

查询慢查询日志存储方法

show variables like '%log_output'

修改慢查询日志存储位置

set global log_output = 'FILE,TABLE'

打印在MySQL中慢查询日志的位置

SELECT * FROM mysql.slow_log

```

默认情况下<font color='orange'>slow_query_log</font>的值为<font color='red'>OFF</font>,表示慢查询日志是禁用的

<font color='cornflowerblue'>那么开启了慢查询日志后,什么样的SQL才会记录到慢查询日志里面呢?</font> 这个是由参数<font color='orange'>long_query_time</font>控制,默认情况下<font color='orange'>long_query_time</font>的值为10秒,可以使用命令修改,也可以在my.cnf参数里面修改。关于运行时间正好等于<font color='orange'>long_query_time</font>的情况,并不会被记录下来。也就是说,在<font color='red'>mysql源码里是判断大于long_query_time,而非大于等于</font>。

## 五、本日重点讲解(不重要的东西)

可移植性不好,不易调试

### 1、触发器

与表有关的数据对象,在满足某种条件的时候,被动执行SQL语句

指事先为某张表<font color='red'>绑定一段代码</font>,当表中的<font color='red'>某些内容发生改变</font>(增、删、改)的时候,系统会<font color='red'>自动触发代码并执行</font>。

#### 作用:

- 可在写入数据前,强制检验或者转换数据(保证护数据安全)

- 触发器发生错误时,前面用户已经执行成功的操作会被撤销,类似事务的回滚

#### 创建触发器

基本语句

```MySQL

delimiter 自定义结束符号

create trigger 触发器名字 触发时间 触发事件 on 表 for each row

begin

    -- 触发器内容主体,每行用分号结尾

end 自定义的结束符合

```

<font color='orange'>on 表 for each</font>:触发对象,触发器绑定的实质是表中的所有行,因此当每一行发生指定改变时,触发器就会发生

##### 触发时间

当 SQL 指令发生时,会令行中数据发生变化,而每张表中对应的行有两种状态:**数据操作前和操作后**

- before:表中数据发生改变前的状态

- after:表中数据发生改变后的状态

**PS**:如果 before 触发器失败或者语句本身失败,将不执行 after 触发器(如果有的话)

##### 触发事件

触发器是针对数据发送改变才会被触发,对应的操作只有

- INSERT:没有 old,只有 new,new 表示将要(插入前)或者已经增加(插入后)的数据

- DELETE:既有 old 也有 new,old 表示更新之前的数据,new 表示更新之后的数据

- UPDATE:没有 new,只有 old,old 表示将要(删除前)或者已经被删除(删除后)的数据

#### 查看触发器

1.查看全部触发器

```MySQL

show triggers;

```

2.查看触发器的创建语句

```MySQL

show create trigger 触发器名字;

```

3.触发触发器

```MySQL

drop trigger 触发器名字;

```

#### 删除触发器

触发器不能修改,只能删除

```MySQL

drop trigger + 触发器名字

```

### 2、存储过程

#### 变量

##### 局部变量

局部变量只在<font color='orange'>BEGIN</font>和<font color='orange'>END</font>的代码块中有效,执行完该代码块,变量就消失,在存储过程中最为常见。<font color='orange'>DECLARE</font>语句专门用于定义局部变量,可以使用<font color='orange'>DEFAULT</font>语句来指明默认值。定义多个变量:<font color='orange'>DECLARE x, y INT DEFAULT 0</font>。赋值用的是`SET`或`SELECT`语句:

```MySQL

DECLARE total_count INT DEFAULT 0

SET total_count = 10;

SELECT COUNT(*) INTO total_count FROM products

```

其中<font color='orange'>total_count</font>为局部变量

##### 用户变量

<font color='red'>用户变量与数据库连接有关</font>,一个客户端定义的变量不能被其它客户端看到或使用。当客户端退出时,该客户端连接的所有变量将失效。用户变量不需要声明,可以直接使用,用户变量以<font color='orange'>@var_name</font>的形式命名变量,<font color='red'>变量名必须以@开头</font>。

赋值语法,一般用<font color='orange'>SET</font>:

```MySQL

set @varName=value;

SELECT @var_name := value;

```

赋值后输出用<font color='orange'>select @varName</font>。

##### 系统变量

MySQL可以访问许多系统变量。当服务器运行时许多变量允许动态更改。这样就可以修改服务器操作而不需要停止并重启服务器。系统变量又包含两种:<font color='red'>会话变量影响具体客户端连接的操作,全局变量影响服务器整体操作。</font>

##### 全局变量

全局变量在 MySQL 启动的时候由服务器自动初始化他们的值, 这些默认的值可以在<font color='orange'>/etc/my.cnf</font>中修改。要想更改全局变量,必须具有<font color='red'>SUPER</font>权限。全局变量作用于<font color='red'>SERVER的整个生命周期</font>,<font color='red'>但重启后所有设置的全局变量均失效</font>。要想让全局变量重启后继续生效,需要更改相应的配置文件。

```MySQL

show global variables like 'wait_timeout%';

```

```mysql

更改等待时间

set global wait_timeout=4;

```

#### 存储过程创建

存储过程是一组已经预先编译好的<font color='orange'>sql</font>语句的集合,理解为批处理语句(增加流程控制语句),一般在复杂逻辑中才会使用存储过程

<font color='red'>存储过程的优点:</font>

- 提供了代码的可用性

- 简化了数据库操作,将业务逻辑的细节隐藏在存储过程中

- 减少了编译次数,减少了网络IO的次数,从而提高操作效率

<font color='red'>存储过程的创建</font>

```cpp

/*

delimiter $

create procedure 存储过程的名称(参数列表)

begin

局部变量的定义

多条sql语句

流程控制语句

eng;$

*/

```

如果存储过程中只有一条<font color='orange'>sql</font>语句可以省略<font color='orange'>begin end</font>

<font color='red'>参数列表</font>

| 参数模式 | 形参名称 | 参数类型                                          |

| :------- | -------- | ------------------------------------------------- |

| in      | username | MySQL数据库中的数据类型(数值型,字符型,日期型) |

| out      | pwd      | MySQL数据库中的数据类型(数值型,字符型,日期型) |

| inout    | xxx      | MySQL数据库中的数据类型(数值型,字符型,日期型) |

<font color='red'>in</font>:声名该参数是一个输入型参数(<font color='orange'>类似Java中的形参</font>)

<font color='red'>out</font>:声名该参数为一个输出型参数(<font color='orange'>类型Java中的返回值</font>),在一个存储过程中<font color='orange'>可以定义多个out类型的参数</font>

<font color='red'>inout</font>:声名该参数可以为输入型参数,也可以为输出型参数

<font color='red'>存储过程调用</font>

```mysql

call 存储过程的名称(实参列表)

-- 实参列表中包含由输出类型的参数

```

<font color='red'>存储过程的演示</font>

- 无参的存储过程

  ```MySQL

  -- 用于b_user表中插入2条数据

  delimiter $ -- 自定义结束标志

  create procedure pro_insert()

  begin

  insert into b_user(name,sex) values('1','1');

  insert into b_user(name,sex) values('2','2');

  end;$

  -- 用这个存储过程

  call pro_insert();

  ```

- 带有<font color='red'>in</font>模式参数的存储过程

  ```MySQL

  -- 用于向b_user插入2条数据,性别由客户输入

  delimiter $

  create procedure pro_insert2(in sex char(1))

  begin

  insert into b_user(name,sex) values('1',sex);

  insert into b_user(name,sex) values('2',sex);

  end;$


  call pro_insert2('男');

  ```

- 带有多个<font color='red'>in</font>模式参数的存储过程

  ```MySQL

  -- 用于向b_user插入2条数据,性别由客户输入

  delimiter $

  create procedure pro_insert2(in name varchar(10),in sex char(1))

  begin

  insert into b_user(name,sex) values(name,sex);

  insert into b_user(name,sex) values(name,sex);

  end;$


  call pro_insert2('name','男');

  ```

- 带<font color='red'>in,out</font>参数的存储过程

  ```MySQL

  -- 判断用户登录,如果用户名和密码输入正确登录成功,否则登录失败

  -- 根据输入的用户名和密码作为条件b_user表中查询,如果查询总行数==1,则认为登录成功,让resukt返回登录成功;否则登录失败

  delimiter $

  create procedure pro_login(in name varchar(20),in pwd varchar(10,out result varchar(20)))

  begin

  declare total int default 0; -- 用于存放查询总行数

  select count(*) from b_user u where u.name= name and u.pwd= pwd; -- 将查询结果赋值给total局部变量

  set result:= if(total=1,'登录成功','登录失败');

  end;$

  -- 存储过程如何执行

  -- 解决判断,使用自定义变量

  set @result:='';

  call pro_login('李四','123',@result);

  select @result;

  ```

- 删除存储过程

  ```MySQL

  drop procedure 存储过程名称

  ```

- 查看存储过程

  ```MySQL

  show create procedure 存储过程名称;

  ```

- 修改存储过程

  ```MySQL

  drop

  create

  ```

#### 流程控制语句

- <font color='red'>if</font>函数结构

  ```cpp

  /*

  if 逻辑表达式 then 语句1;

  elseif 逻辑表达式2 then 语句2;

  …………

  else 语句n;

  end if;

  */

  ```

- <font color='red'>case</font>结构

  等值选择

  ```MySQL

  case 字段|变量|表达式

  when 值 then 值|语句

  when 值 then 值

  …………

  else 值

  end

  ```

  不等值选择

  ```MySQL

  case

  when 逻辑表达式 then 语句1

  ……

  else 语句n

  end

  ```

- <font color='red'>循环结构</font>

  while

  ```mysql

  /*

  while 逻辑表达式 do

  循环体

  end while;

  */

  -- 需求:创建存储过程,输入一个值,返回1到该值的和

  delimiter $

  create procedure pro_sum(in input int,out total int)

  begin

  declare i int default 1;

  declare sum_ int default 0;

  while i<=input do

  set sum_=sum_+i;

  set i=i+1;

  end while;

  set total:=sum_;

  end;$


  set @result:=0;

  call pro_sum(10,@result);

  select @result;

  ```

- repeat

  ```mysql

  repeat

  循环体

  until 逻辑表达式 -- 当满足逻辑表达式,跳出循环

  end repeat;


  delimiter $

  create procedure pro_sum_loop(in input int,out total int)

  begin

  declare i int default 1;

  declare sum_ int default 0;

  repeat

  set sum_:=sum_+i;

  set i:=i+1;

  until i>input

  end REPEAT;

  set total:=sum_;

  end;$


  set @result:=0;

  call pro_sum(10,@result);

  select @result;

  ```

### 3、存储函数

##### 1. 存储函数:

- 函数(Function)为一命名的存储程序,可带参数,并返回一计算值.

- 函数和过程的结构类似,但必须有一个return子句,用于返回函数值.

##### 2. 创建存储函数的语法:

```kotlin

create [or replace] function 函数名(参数列表)

return 函数值类型

as

PLSQL子程序体;

```

<font color='red'>注意事项:</font>

- (1) 与存储过程注意事项类似,不同的是,**必须有个返回值**;

- (2) 参数列表可以有,也可以没有.当没有时,函数名后面不要带括号.

```rust

create or replace function queryempannal(pempno in number)

return number

as

  psal emp.sal%type;

  pcomm emp.comm%type;

begin

  select sal,comm into psal,pcomm from emp where empno=pempno;

  return psal*12+nvl(pcomm,0);

end;

```

删除函数:

```MySQL

drop function 函数名;

```

### 4、定时任务

#### 查看任务是否开启

```MySQL

show variables like '%event_sche%';

```

开启定时策略

```MySQL

set global event_scheduler=1;

```

#### 创建定时任务

```MySQL

create event run_event

on schedule every 1 minute

on completion preserve disable

do call test_procedure ();

```

- create event day_event:是创建名为run_event的事件

- 创建周期定时的规则,意思是每分钟执行一次

- on completion preserve disable是表示创建后并不开始生效。

- do call test_procedure ()是该event(事件)的操作内容

#### 定时任务操作

查看

```MySQL

SELECT event_name,event_definition,interval_value,interval_field,status

FROM information_schema.EVENTS;

```

开启或关闭

```MySQL

alter event run_event on completion preserve enable;//开启定时任务

alter event run_event on completion preserve disable;//关闭定时任务

```

#### 定时规则

周期执行–关键字 EVERY

单位有:<font color='red'>second、minute、hour、day、week(周)、quarter(季度)、month、year</font>

```MySQL

on schedule every 1 week //每周执行1次

```

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 今天感恩节哎,感谢一直在我身边的亲朋好友。感恩相遇!感恩不离不弃。 中午开了第一次的党会,身份的转变要...
    余生动听阅读 10,911评论 0 11
  • 彩排完,天已黑
    刘凯书法阅读 4,497评论 1 3
  • 表情是什么,我认为表情就是表现出来的情绪。表情可以传达很多信息。高兴了当然就笑了,难过就哭了。两者是相互影响密不可...
    Persistenc_6aea阅读 129,814评论 2 7

友情链接更多精彩内容