高性能MYSQL(学习笔记)-MySQL高级特性2

视图

概念和特点:

1、  视图是一张虚拟表,本身不存放任何数据

2、  视图返回数据是从MySQL其他表生成

3、  重用SQL语句、简化复杂的SQL操作,可以方便重用而隐藏底层查询细节

4、  使用表的部分列而不是整张表权限

5、  保护数据,提供某些权限给用户而不是整张表权限

限制

视图必须唯一命名(名称不能和表相同)、数量不限、创建视图需要授权、可以嵌套、视图不能索引,不能有关联的触发器或默认值、可以和表一起使用。

例子:

CREATE VIEW Oceania AS SELECT * FROM country where continent=‘Oceania’ with check option

实现视图方法是将select 语句结果存放到临时表中,当需要访问数据时,直接访问此临时表:selectcode,name from oceania where name=’China’;

下面是使用临时表模拟视图的方法:create template table tmp_oceania as select * from country wherecontinent=’oceania’;

Select code,name from tmp_oceania where name = ‘China’;

这样会有明显的性能问题,优化器很难优化这个临时表上的查询,实现视图更好的方法是重写含有视图的查询,将视图定义SQL直接包含进查询的SQL中。

Select code,name from country where continent = ‘oceania’ and name=’australia’;

MySQL可以使用这两种方法来处理视图,成为合并算法(MERGE)和临时表算法(TEMPTABLE),尽可能使用合并算法,如果采用临时表算法,EXPLAIN会显示派生表(DERIVED)。

如果视图中包含 GROUP BY 、DISTINCT、任何的聚合函数、UNION、子查询等,只要无法再原表记录和视图记录中建立一一映射的场景中,MySQL都将使用临时表算法实现视图。

可更新视图

UPDATABLE VIEW 指的是可以通过更新这个视图来更新视图涉及的相关表,只要指定了合适的条件就可以更新、删除甚至写入数据:

Update oceaniaset population = population*1.1 where name =’australia’;

但是如果视图定义中包含了group by、union、聚合函数以及其他情况,就不能被更新了,所有临时表算法实现的视图都无法被更新!!!

不能更新视图定义列以外的列!!!

外键约束

InnoDB是目前MySQL中唯一支持外键的内置存储引擎,使用外键是有成本的,比如外键通常都要求每次在修改数据时都要在另外一张表中执行一次查找操作,虽然InnoDB强制外键使用索引,但是无法消除这种约束检查的开销。如果外键列的选择很低,那么导致一个非常大且选择性很低的索引。

外键也会提升一些性能,例如想确保两个相关表始终有一致的数据,那么使用外键比在应用程序中检查一致性的性能要高很多。外键在相关数据的删除和更新上,比在应用中维护高效很多,不过外键维护操作是逐行进行的,这样的更新会比批量删除和更新慢。

如果只是使用外键做约束,那通常在应用程序里实现约束会更好,外键会带来额外的开销!

在MySQL内部存储代码

MySQL允许通过触发器、存储过程、函数的形式来存储代码,MySQL5.1开始还能在定时任务中存放代码,也被称为“事件”,存储过程和存储函数统称为“存储程序”。存储过程和存储函数都可以接收参数然后返回值,到那时触发器和事件却不行。MySQL中使用存储代码的优点:

1、  在服务器内部执行,离数据近,在服务器上可以节省带宽和网络延迟。

2、  这是一种代码重用,可以方便地统一业务规则,保证某些行为总是一致,所以也可以应用提供一定的安全性。

3、  简化代码维护和版本更新。

4、  提升安全,提供更细粒度的权限控制,比如银行用于转移资金的存储过程:这个存储过程可以在一个事务中完成资金转移和记录用于审计的日志。这个存储过程可以再一个事务中完成资金转移和记录用于审计的日志。

5、  服务器端可以缓存存储过程的执行计划,对于需要反复调用的过程,会大大降低消耗。

6、  因为是部署在服务端的,所以备份、维护都可以再服务器端完成,所以存储程序的维护工作都会很简单,没有什么外部依赖。

7、  可以在应用开发和数据库开发人员之间更好的分工,不过最好是由数据库专家来开发存储过程,因为不是每个应用开发人员都能写出高效的MySQL查询。

存储代码的缺点:

1、  MySQL本身没有提供好用的开发和调试工具,编写MySQL的存储代码比其他的数据库要更难。

2、  存储代码比应用程序的代码效率稍差,使用的函数有限,

3、  存储代码给应用程序代码部署带来额外的复杂性,需要额外布置额外的MySQL内部存储代码

4、  因为存储程序都在服务器内,所以有安全隐患,攻击者只需要攻破数据库就可以。

5、  存储过程会给服务器增加额外的压力,数据库服务器的扩展性比应用服务器差。

6、  MySQL没有选项可以控制存储程序的资源消耗,存储过程的一个下问题,可能直接把服务器拖死。

7、  MySQL较PL/SQL、T-SQL的存储代码功能还是比较弱

8、  调试MySQL的存储过程是一个困难的事

存储过程和函数

MySQL架构本身和优化器的特性使得存储代码有一些天然的限制,他的性能也受限于此:

1、  优化器无法使用关键字DETERMINISTIC来优化单个查询中多次调用存储函数的情况

2、  优化器无法评估存储函数的执行成本

3、  每个连接器都有独立的存储过程的执行计划缓存,如果有多个连接需要调用同一个存储过程,将会浪费缓存空间来反复缓存同样的执行计划,使用的是连接池或者持久化连接那么执行缓存计划可能会有更长的生命周期

4、  存储程序和复制是一个诡异组合,如果可以不要复制对存储程序的调用。

   不过,对于一些操作,存储过程比其他的要快得多——特别是当一个存储过程调用可以代替很多小查询的时候,如果查询很小,相比这个查询执行成本,解析和网络开销就变得非常明显。

触发器

     触发器可以在让你执行INSERT、UPDATE或者DELETE的时候,执行一些特定的操作。可以在MySQL上指定是在SQL语句执行前触发还是在执行后触发,触发器本身不反悔值,但是可以读取或者改变触发SQL语句影响的数据。触发器使用中需要注意几点:

1、  对每一个表的每一个事件,最多只能定义一个触发器(不能在AFTER INSERT 上定义两个触发器)

2、  MySQL只支持基于行的触发,也就是说触发器始终是针对一条记录,而不是针对整个SQL语句。

3、  触发器可以掩盖服务器背后的工作一个简单的SQL语句背后,因为触发器可能包含了很多看不见的工作

4、  触发器的问题很难排查,如果某个性能问题和触发器相关,很难分析和定位。

5、  触发器可能导致死锁和锁等待,如果锁失败那么原来的SQL语句也会失败。

如果仅考虑性能,那么MySQL触发器的实现对服务器限制最大的就是它的“基于行的触发”设计,因为性能原因,他很多时候无法使用触发器来维护汇总和缓存表。

MyISAM触发器无法保证更新的原子性,也就说没有办法回滚操作的,当建立一个AFTER UPDATE的触发器,用来更新另外一个MyISAMbiao ,如果在更新第二张表时候失败,第一张表是不会回滚的。

InnoDB表上的触发器是在同一个事务中完成的,它们执行操作是原子性的,同时失败或者同时成功。

事件

MySQL事件类似于Linux的定时任务,不过完全在MySQL内部中实现,可以创建事件让MySQL在某一个时候执行一段代码或者每隔一个时间执行一段SQL代码,通常会把复杂的SQL都封装成一个存储过程中,这样事件在执行的时候只需要做一个简单的CALL调用。

一些存储过程的考虑也可以同样适用于事件,创建事件意味着给服务器带来额外的工作,事件实现本身的开销不大,但是时间需要执行SQL则可能对性能有很大的影响,事件的一些典型应用包括:定期维护任务、重建缓存、构建汇总表来模拟物化视图,存储用于监控和诊断的状态值。

注:

如果一个定时事件执行需要很长的时间,那么有可能出现事件冲突情况,MySQL本身不会防止这种并发,所以用户需要自己编写这种情况防止并发代码,可以使用GET_LOCK()来确保当前只有一个事件在被执行:

CREATE EVENT optimize_somedb ONSCHEDULE EVERY 1 WEEK

DO

BEGIN

   DECLARE CONTINUE HANLDER FOR SQLEXCEPTOIN

     BEGIN END;

IF GET_LOCK(‘somedb’,0) THEN

  DO CALLoptimize_tables(‘somedb’);

END IF;

DO RELEASE_LOCK(‘somedb’);

END

这里的“CONTINUE HANLDER”用来确保,即使当事件执行出现了异常,仍然会释放持有的锁。

绑定变量

MySQL支持服务端的绑定变量,这样提高了客户端和服务端数据传输的效率,当创建一个绑定变量的SQL语句时,客户端向服务器发送了一个SQL语句的原型服务端收到后,解析并存储这个SQL语句的部分执行计划,返回给客户端一个SQL语句的处理句柄,以后每次执行这类查询,客户端都指定使用这个句柄。

INSERT INTO tb1(col1,col2,col3)VALUES(?,?,?);可以通过向服务器端发送这个问好的取值和之歌SQL的句柄来执行一个具体的查询。MySQL在使用绑定变量的时候可以高效的执行大量的重复语句,原因在于:

1、  服务器端只需要解析一次SQL语句

2、  服务器端某些优化器的工作只需要执行一次,因为他会缓存一部分的执行计划。

3、  以二进制的方式只发送参数和句柄,比起每次都发送ASCII码文本效率更高。二进制协议在客户端能节省很多内存,减少网络开销

4、  仅仅是参数而不是整个查询语句需要发送到服务器端,网络开销更小

5、  在存储参数时,直接将其放在缓存中,不需要再内存中多次复制。

6、  相对安全,无需再应用程序中处理转义,简单并且减少SQL注入和攻击风险。

绑定变量的优化

优化分为三类:

1、  准备阶段,服务器解析SQL语句,移除不可能的条件,并重写子查询

2、  第一次执行时候,服务器先简化嵌套循环的关联,并将外关联转化成内关联

3、  每次SQL语句执行时,过滤分区、尽量移除 COUNT().MIN(),MAX()、移除常数表达式、检测常量表、做必要的等值传播、分析和优化ref、range和索引优化等访问数据的方法、优化关联顺序。

有些优化只需要做一次,但是上面的操作还是都会被执行。

绑定变量的限制

关于绑定变量的限制和注意项如下:

1、  绑定变量是会话级别,连接之间不能共用绑定变量句柄,一旦链接断开,原来句柄也不能再使用了。(连接池和持久化连接在一定程度上缓解这个问题)

2、  Mysql5.1版本前,绑定变量的SQL是不能使用查询缓存的

3、  并不是所有时候使用绑定变量都能获得更好的性能,如果只执行一次SQL那么使用绑定变量方式无疑比直接执行多了一次额外的准备阶段消耗,还需要一次网络开销

4、  当前版本下,还不能在存储函数中使用绑定变量

5、  如果忘记释放绑定变量,则服务器端很容易发生资源泄露

6、  有些操作如BEGIN,无法在绑定变量中完成。


你可能感兴趣的:(高性能MYSQL学习笔记)