高性能MySQL之锁粒度(二)

无论什么时候,只要有多个查询需要同一时刻修改数据,都会产生并发控制问题。关于并发控制的问题,我们将会介绍一个新的概念-锁。我们在多线程编程中会经常使用锁来进行并发控制。那么,MySQL针对并发控制做了哪些努力呢?或者说,MySQL的锁粒度主要是哪几种呢?

锁粒度

一种提高共享资源并发性的方式就是让锁定对象更有选择性。尽量只锁定需要修改的部分数据,而不是所有的资源。为什么这样呢?我们都知道,一旦锁定了,这部分资源相对其他的请求就不可用了,他们必须等待这部分资源被释放以后才能申请使用这部分资源。而在多线程的环境下,假设有上百个线程同时在访问某一张表,如果某一个线程需要修改某一条数据,而它将整张表都锁定了,那么其他的上百个线程都必须等待,这样我们的程序并发性就大大被降低了。如果我们只锁定其中被修改的那行数据,那么我们修改这条数据时将不会影响其它的线程访问它们需要的数据,并发性将会大大提高。也就是说,在任何时候,在给定的资源上,锁定的数据量越少,则系统的并发程度越高,只要相应之间不发生冲突即可。

问题是加锁也需要消耗资源。锁的各种操作,包括获得锁、检查锁是否已经被释放、释放锁等,都会大大增加系统的开销。如果系统花费了大量的时间来管理锁,而不是存取数据,那么系统的性能将会受到大大地影响。

所谓的锁策略,就是在锁的开销和数据的安全性之间寻求平衡,这种平衡当然也会影响到性能。大多数商业数据库没有提供更多的选择,一般都是在表上施加行级锁,并以各种复杂的方式来实现。

表锁(table lock)

表锁是MySQL中最基本的锁策略,并且是开销最小的策略。表锁就是我们前面在锁粒度这里提到的资源访问控制机制:它会锁定整张数据表。一个用户对某一张表进行写操作(更新,插入,删除等)前,一定要先获取这张表的写锁,这个写锁会阻塞其他所有的用户对于这张表的读操作和写操作。只有当没有写锁的时候,其他的用户才能获得这张表的读锁,读锁之间是不会互相阻塞的。

在特定的场景中,表锁也能拥有良好的性能。例如,READ LOCAL表锁支持某些类型的并发写操作。另外,我们也需要知道的一点是,写锁比读锁具有更高的优先级,因此当一个用户向数据表中写入数据的时候,其他所有用户的读操作都必须中断等待。也就是说写锁的请求会被插入到读锁队列的前面,优先执行。

尽管存储引擎可以管理自己的锁,但是MySQL本身还是会使用各种不同的表锁来实现不同的目的。例如,服务器会为诸如ALTER TABLE之类的语句使用表锁,而忽略存储引擎的锁机制。

行级锁(row lock)

行级锁可以最大化程度地支持并发处理(同时也带来了最大的锁开销)。众所周知,在InnoDB和XtraDB,以及一些其他的存储引擎汇总实现了行级锁,MyISAM存储引擎中可没有啊,这个很重要!行级锁只在存储引擎层实现,而MySQL服务层没有实现。服务器层完全不了解存储引擎中的锁实现。所有的存储引擎都以自己的方式显式实现了锁机制。

参考文献:《高性能MySQL》

分享到