为什么在高并发的场景下,需要将 MySQL 的事务隔离级别设为读已提交?

标签:性能

为缩短篇幅,本文假定读者已知晓 transaction isolation level(事务隔离级别)的基础知识。

MySQL 的默认事务隔离级别是 repeatable read(可重复读),而在都市传说中,各个互联网大厂都会将其改为 read committed(读已提交),这是为什么呢?

从字面上理解,可重复读满足了一个事务在读取某行后,如果另一个事务修改了该行,再次读取它时,能保持第一次读到的值。可是,这又有什么意义呢?谁会在一个事务里多次读取同一行呢?
其实它的实现是这样:当事务开始后,从它第一次读取数据时,就创建了一个快照,之后都是对这个快照进行查询,直到这个事务结束。也就是说,可重复读的主要作用是让事务只访问这个事务和它之前已有的数据,而不是字面上的读同一行不会变。
而读已提交只需要在每次读取时创建一个快照,读取完这个快照就用不到了。
由此可见,可重复读需要维护一个较长的快照,这自然要消耗更多的资源。

不过现实中我们不会这样简单地使用事务。一个正常的事务如果要基于读取到的数据来修改,会使用 SELECT ... FOR UPDATE 的形式来加锁。
如果这里可以利用唯一索引的话,MySQL 会对唯一索引中满足条件的行添加行锁,否则需要加 gap lock 和 next-key lock,这两把锁会增加被锁定的范围。例如表 test 有一个被索引的列 a,有一行 a 为 100 的数据。当执行 SELECT * FROM test WHERE a = 1 FOR UPDATE 后,其他事务无法插入任何 a < 100 的数据,因为被这两把锁给锁住了。
而读已提交则不会添加这两种锁,并且当需要锁住的行不存在时,并不会对其加锁,而是允许其他事务插入。
由此可见,可重复读可能锁住了更多的数据,更容易造成死锁。

关于 Redis 的几种数据库设计方案的内存占用测试

标签:Python, 性能, Redis

最近在做一个项目,数据库使用的是 Redis。在设计数据结构时,不知道哪种实现是最优的,于是做了下测试。

测试环境如下:
OS X10.8.3
Redis 2.6.12
Python 2.7.4
redis-py 2.7.2
hiredis 0.1.1
ujson 1.30
MessagePack 0.3.0
注意:
  1. 因为是拿 Python 测试的,所以可能对其他语言并不完全适用。
  2. 使用的测试数据是特定的,可能对更小或更大的数据并不完全适用。

字符串相加并不慢

标签:Python, 性能, JavaScript, Java

在学Java时,我对拼接字符串有个很深刻的印象:StringBuilder.append()比String相加要快很多。
这个偏见影响了我几年,直到今天才发现它并不一定适用于其他语言。

关于socket的一些初步研究

标签:性能

这些天在研究Tornado的源码,说实话它的代码过于艰深了,需要绕很多弯才能弄清。
我想其中的问题主要是我不太懂socket,于是就花了些时间学习socket,算是有了些收获,顺便记录在此。

« 看看还有什么好玩意