《高性能mysql》札记第一波(一)

2015-01-23 22:03:53 · 作者: · 浏览: 13

事务就是一组原子性的SQL查询,或者说一个独立的工作单元。那么如果数据库引擎能够成功的执行该组内的所有语句,那么就执行该组语句。如果其中有任何一条语句执行失败,则所有语句都不执行。也就是说,事务内的语句,要么全部执行,要不都不执行。然后是事务的ACID特征。 原子性:一个事务必须被视作一个不可分割的最小单元。整个事务中的所有操作要么全部执行成功,否则全部回滚,不可能只执行其中一部分,确保事务内的所有语句是一个原子。一致性:数据库总是从一个一致性的状态到另外一个一致性的状态。如果事务中一条语句执行失败,任何已经执行成功的语句也不会保存到数据库中。隔离性:通常情况下(这个因事务隔离级别有不同的情况),一个事务在最终提交之前,对其他事务时不可见的,注意是通常情况。持久性:一旦事务提交,则其所作的修改就会永久保存到数据库中。这个概念我本人还没有很好的理解(比如对与innodb来说,其中的一个参数innodb_flush_log_at_trx_commit,对于事务的提交后数据写入磁盘的时间点有很大的不同。) 一个实现了ACID的数据库,比如对于mysql数据库,通常会需要更强的CPU处理能力、更多的磁盘空间、更大的内存大小。但具体需要什么样的配置,我也没有找出合理的方案,对于我们的期货交易平台,到底需要什么样的配置更合理。隔离级别(每一种级别都规定了一个事务中所做的修改,哪些在事务内和事务间是可见的,哪些不可见。较低级别的隔离通常可以执行更高的并发,系统的开销个更低): READ UNCOMMITTED(未提交读):在这个级别,事务中的修改,即使没有提交,对其他事务也都是可见的。事务可以读取未提交的数据(被称为脏读),这种级别会有很多问题,性能也不会比其他级别好,不推荐使用。READ COMMITTED(提交读):一个事务开始时,只能看见已经提交的事务所作的修改,换言之,就是只要该事务没有提交,其他事务是无法看见本事务已经做的修改。REPEATABLE READ(可重复读):该级别保证了同一个事务中多次读取同样记录的结果是一致的(这块我稍后会做出测试,但是有疑问),对于mysql的innodb引擎来说,该引擎使用了MVCC模式进行控制,解决了幻读的问题,但是理论上,其他的引擎如果没有解决幻读的问题时,会出现幻行(对于幻读和幻行,稍后再进行研究)。mysql默认的隔离级别为可重复读。SERIALIZABLE(可串行化):它强制事务串行执行,避免了幻读的问题。简单来说,该级别时,事务在读取到每一行数据时都会加锁,所以可能导致大量的争锁和超时问题,实际应用下,很少用到。 自动提交(AUTOCOMMIT):mysql默认采用自动提交模式。也就是说,如果不显式的开始一个事务,则每个查询都会被当作一个事务提交。也这样说,如果显示的开始一个事务,就是说使用了start transaction开启事务的时候,事务内的所有查询不再分离成一个个小的事务进行提交操作。事务日志:事务日志可以帮助提高事务的效率,存储引擎在修改表的数据时只需要修改你内存拷贝,再把修改行为记录到持久在硬盘上的事务日志中,而不用每次都将修改的数据持久到磁盘。事务日志采用的是追加的方式,因此写日志的操作时磁盘上一小块区域内的顺序IO,所以采用事务日志的方式相对来说快很多。事务日志持久后,内存中修改的数据在后台可以慢慢的刷回磁盘,修改数据需要写两次磁盘。如果修改的数据已经记录到事务日志并持久化,即使数据本身还没有写回磁盘,操作系统崩溃了,存储引擎在重启时能够自动回复这部分数据。

实践
提交读和可重复读的区别 提交读的隔离级别下,我们进行下面的试验,验证“一个事务从开始知道提交之前,所作的任何修改对其他事务都是不可见的”,先测试insert的情况
事务1 事务2
mysql> show variables like 'tx_isolation';
+---------------+----------------+
| Variable_name | Value |
+---------------+----------------+
| tx_isolation | READ-COMMITTED |
+---------------+----------------+
1 row in set


mysql> start transaction;
Query OK, 0 rows affected


mysql> select * from test;
+----+-------+
| id | value |
+----+-------+
| 1 | 1 |
| 2 | 2 |
+----+-------+
2 rows in set
1
2 mysql> start transaction;
Query OK, 0 rows affected


mysql> select * from test;
+----+-------+
| id | value |
+----+-------+
| 1 | 1 |
| 2 | 2 |
+----+-------+
2 rows in set


mysql> insert into test values(3,3);
Query OK, 1 row affected


mysql> select * from test;
+----+-------+
| id | value |
+----+-------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
+----+-------+
3 rows in set
mysql> select * from test;
+----+-------+
| id | value |
+----+-------+
| 1 | 1 |
| 2 | 2 |
+----+-------+
2 rows in set
3
4 mysql> commit;
Query OK, 0 rows affected
mysql> select * from test;
+----+-------+
| id | value |
+----+-------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
+----+-------+
3 rows in set


mysql> commit;
Query OK, 0 rows affected
5
? ?
通过上面的顺序执行,可以看出来“一个事务开始时,只能看到已经提交的事务所作的修改”,并且“一个事务从开始直到提交之前,所作的任何修改对其他事务都是不可见的”,然后在一个事务内“两次执行同样的查询,可能会得到不一样的结果”。
隔离级别不变,测试update情况
事务1 事务2
mysql> show variables like 'tx_isolation';
+---------------+----------------+
| Variable_name | Value |
+---------------+----------------+
| tx_isolation | READ-COMMITTED |
+---------------+----------------+
1 row in set


mysql> start transaction;
Query OK, 0 rows affected


mysql> select * from test;
+----+-------+
| id | value |
+----+-------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
+----+-------+
3 rows in set
1
2 mysql> start tr