• 事务操作的统计,TPS的计算,隔离级别的读提交


    对于事务操作的统计

    因为InnoDB存储引擎是支持事务的,因此对于InnoDB存储引擎的应用,在考虑每秒请求数(Question Per Second,QPS)的同时,也许更应该关注每秒事务处理的能力(Transaction Per Second,TPS)。

    计算TPS的方法是(com_commit+com_rollback)/time。但是用这种方法计算的前提是:所有的事务必须都是显式提交的,如果存在隐式的提交和回滚(默认autocommit=1),不会计算到com_commit和com_rollback变量中。如:

    show global status like 'com_commit'G  5

    insert into t select 3;

    select * from tG

    show global status like'com_commit'G  5

    MySQL另外还有2个参数handler_commithandler_rollback。但是我注意到,这两个参数在MySQL 5.1中可以很好地用来统计InnoDB存储引擎显式和隐式的事务提交操作,而在InnoDB Plugin中该参数的表现有些“怪异”,并不能很好地统计事务的次数。所以,如果你的程序都是显式控制事务的提交和回滚,那么可以通过com_commit和com_rollback进行统计。如果不是,那么情况就显得复杂了。

    事务的隔离级别

    令人惊讶的是,大部分数据库系统都没有提供真正的隔离性,最初或许是因为系统实现者并没有真正理解这些问题。如今这些问题已经弄清楚了,但是数据库实现者在正确性和性能之间做了妥协。ISO和ANIS SQL标准制定了四种事务隔离级别的标准,但是很少有数据库开发厂商遵循这些标准,比如Oracle数据库就不支持read uncommitted和repeatable read的事务隔离级别。

    SQL标准定义的四个隔离级别为:

    1. READ UNCOMMITTED
    2. READ COMMITTED
    3. REPEATABLE READ
    4. SERIALIZABLE

    READ UNCOMMITTED称为浏览访问(browse access),仅仅只对事务而言的。

    READ COMMITTED称为游标稳定(cursor stability)。

    REPEATABLE READ是2.9999˚的隔离,没有幻读的保护。

    SERIALIZABLE称为隔离,或3˚。SQL和SQL 2标准的默认事务隔离级别是SERIALIZABLE。

    InnoDB存储引擎默认的支持隔离级别是REPEATABLE READ,但是与标准SQL不同的是,InnoDB存储引擎在REPEATABLE READ事务隔离级别下,使用Next-Key Lock锁的算法,因此避免幻读的产生。这与其他数据库系统(如Microsoft SQL Server数据库)是不同的。所以说,InnoDB存储引擎在默认REPEATABLE READ的事务隔离级别下已经能完全保证事务的隔离性要求,即达到SQL标准的SERIALIZABLE隔离级别。

    隔离级别越低,事务请求的锁越少,或者保持锁的时间就越短。这也是为什么大多数数据库系统默认的事务隔离级别是READ COMMITTED。

    在InnoDB存储引擎中,可以使用以下命令来设置当前会话或者全局的事务隔离级别:

    SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL

    {

      READ UNCOMMITTED

      |READ COMMITTED

      |REPEATABLE READ

      |SERIALIZABLE

    }

    如果想在MySQL库启动时就设置事务的默认隔离级别,那就需要修改MySQL的配置文件,在[mysqld]中添加如下行:

    [mysqld]

    transaction-isolation=READ-COMMITTED

    查看当前会话的事务隔离级别,可以使用:

    select @@tx_isolationG

    查看全局的事务隔离级别,可以使用:

    select @@global.tx_isolationG

    在SERIALIABLE的事务隔离级别,InnoDB存储引擎会对每个SELECT语句后自动加上LOCK IN SHARE MODE,即给每个读取操作加一个共享锁。因此在这个事务隔离级别下,读占用锁了,一致性的非锁定读不再予以支持。因为InnoDB存储引擎在REPEATABLE READ隔离级别下就可以达到3˚的隔离,所以一般不在本地事务中使用SERIALIABLE的隔离级别,SERIALIABLE的事务隔离级别主要用于InnoDB存储引擎的分布式事务。

    在READ COMMITTED的事务隔离级别下,除了唯一性的约束检查以及外键约束的检查需要Gap Lock,InnoDB存储引擎不会使用Gap Lock的锁算法。但是使用这个事务隔离级别需要注意一些问题。首先,在MySQL 5.1中,READ COMMITTED事务隔离级别默认只能工作在Replication(复制)的二进制日志为ROW的格式下。如果二进制日志工作在默认的STATEMENT下,则会指出如下的错误:

    create table a(b int,primary key(b))engine=innodb;

    set @@tx_isolation='read-committed';

    select @@tx_isolationG

    begin;

    insert into a select 1;

    ERROR 1598(HY000):Binary logging not possible.Message:Transaction level

    'READ-COMMITTED'in InnoDB is not safe for binlog mode'STATEMENT'

    MySQL 5. 0版本之前不支持ROW格式的二进制日志时,也许有人知道,可以通过将参数innodb_locks_unsafe_for_binlog设置为1,来使得可以在二进制日志为STATEMENT下使用READ COMMITTED的事务隔离级别:

    select @@versionG

    system cat/etc/my.cnf | grep innodb_locks_unsafe_for_binlog

    innodb_locks_unsafe_for_binlog=1

    show variables like 'innodb_locks_unsafe_for_binlog'G

    ***************************1.row***************************

    Variable_name:innodb_locks_unsafe_for_binlog

    Value:ON

    set @@tx_isolation='read-committed';

    begin;

    insert into a select 1;

    commit;

    是的,的确可以通过上述办法使得在MySQL 5.0的版本之前使用READ COMMITED事务隔离级别。但是就像参数innodb_locks_unsafe_for_binlog的名称一样,它是unsafe的。在某些情况下,可能会导致master和slave之间数据的不一致。

    接着来演示一种可能导致不同步的情况,首先来看下表a中的数据:

    select * from aG

    ***************************1.row***************************

    b:1

    ***************************2.row***************************

    b:2

    ***************************3.row***************************

    b:4

    ***************************4.row***************************

    b:5

    4 rows in set(0.00 sec)

    接着在master上开启一个会话A执行如下事务,并且不要提交:

    #Session A on master

    begin;

    delete from a where b<=5;

    在master上开启另一个会话B,执行如下事务,并且提交:

    #Session B on master

    begin;

    insert into a select 3;

    commit;

    接着会话A提交,并查看表a中的数据:

    #Session A on master

    commit;

    select * from aG

    ***************************1.row***************************

    b:3

    但是在slave上看到的结果却是:

    #Slave

    select * from a;

    可以看到,数据产生了不一致。导致这个问题发生的原因有两点:首先,在READ COMMITTED事务隔离级别下,事务是没有Gap Lock锁的,因此我们可以在小于等于5的范围内再插入一条记录;其次,statement记录的是master上产生的SQL语句,因此在master上是先删后插,但是在STATEMENT格式中记录的却是先插后删,逻辑上就产生了不一致。因此,使用READ REPEATABLE事务隔离级别就可以避免第一种情况的发生,因而也就避免了master和slave不一致问题的产生。

    在MySQL 5.1的版本之后,因为支持了ROW格式的二进制日志记录格式,所以避免了第二种情况的发生,因此可以放心使用READ COMMITTED的事务隔离级别。即使不使用READ COMMITTED的事务隔离级别,也应该考虑将二进制日志的格式更换成ROW,因为这个格式记录的是行的变更,而不是简单的SQL语句,因此可以避免一些不同步现象的产生。

  • 相关阅读:
    数据存储之iOS断点续传
    使用MVC4,Ninject,EF,Moq,构建一个真实的应用电子商务SportsStore(十一)
    使用MVC4,Ninject,EF,Moq,构建一个真实的应用电子商务SportsStore(十)
    使用MVC4,Ninject,EF,Moq,构建一个真实的应用电子商务SportsStore(九)
    获取当前页面url中的参数 coffeescript+node.js+angular
    自定义异步线程池工具,用于执行异步方法
    @ComponentScan 扫包 @Import添加组件
    properties解决中文乱码
    Spring Cloud Config配置中心(五)
    Spring Cloud Zuul路由转发(四)
  • 原文地址:https://www.cnblogs.com/wade-luffy/p/6305793.html
Copyright © 2020-2023  润新知