《高性能MySQL》第三版勘误表

《高性能MySQL》第三本勘误表,欢迎各位反馈书中的问题,我们将尽量在再次印刷的时候修正这些问题,谢谢大家。
购买链接: Amazon 京东 当当

1. 译者序vi 倒数第2段第3行
其中,我负责前、推荐序和第1、2、3章 修改为 其中,我负责前言、推荐序和第1、2、3章

注:2013年5月第二次印刷已经订正

2. P57第7行
rdnwr 修改为 rndwr

注:2013年5月第二次印刷已经订正

3. P227第4行(感谢@半个馒头大师指正)
我们希望返回所有包含同一个演员参演的电影 修改为 我们希望返回所有有演员参演的电影

注:2013年7月第三次印刷已经订正

4. P227第12行(感谢@半个馒头大师指正)
很容易表达“包含同一个参演演员“的逻辑 修改为 很容易表达“有演员参演“的逻辑

注:2013年7月第三次印刷已经订正

5. P422第3行(感谢@hongbin119指正)
noop调度适合没有自己的调度算法的设备 修改为 noop调度适合那些自己在背后实现了调度算法的设备

注:2013年7月第三次印刷已经订正

《高性能MySQL》(第3版)中文版

历经差不多一年的时间,总算让《高性能MySQL》(第3版)中文版可以和大家见面了,今天Amazon和China-pub已经开始预售,其他网站这几天也都会开始上架。预计4.10可以正式出阁了。

Amazon预售地址
China-pu预售地址
在线试读 第2章 第3章 第4章

翻译是件苦差事,初稿出来后,大规模审稿两三次,身心俱疲,大量内容在审稿过程中都被重新修改润色。直到上个周末,最后又快速的过了一次,修正了几十处不太满意的小地方。只要没有最终正式交付给出版社,每看一遍都能找出很多可以改进的地方。因此,然后已经交付付印,心中依然怀有忐忑,期望不要有误导人的错误遗留其中。

内容简介

《高性能MySQL(第3版)》是MySQL 领域的经典之作,拥有广泛的影响力。第3 版更新了大量的内容,不但涵盖了最新MySQL 5.5版本的新特性,也讲述了关于固态盘、高可扩展性设计和云计算环境下的数据库相关的新内容,原有的基准测试和性能优化部分也做了大量的扩展和补充。全书共分为16 章和6 个附录,内容涵盖MySQL 架构和历史,基准测试和性能剖析,数据库软硬件性能优化,复制、备份和恢复,高可用与高可扩展性,以及云端的MySQL 和MySQL相关工具等方面的内容。每一章都是相对独立的主题,读者可以有选择性地单独阅读。

本书不但适合数据库管理员(DBA)阅读,也适合开发人员参考学习。不管是数据库新手还是专家,相信都能从本书有所收获。

译者序

  在互联网行业,MySQL 数据库毫无疑问已经是最常用的数据库。LAMP(Linux +Apache + MySQL + PHP)甚至已经成为专有名词,也是很多中小网站建站的首选技术架构。我所在的公司淘宝网,在2003 年非典肆虐期间创立时,选择的就是LAMP 架构,当时MySQL 的版本还是4.0。但是到了2003 年底,由于业务超预期的增长,MySQL 4.0(当时用的还是MyISAM 引擎)的很多缺点在高并发大压力下暴露了出来,于是技术上开始改用商业的Oracle 数据库。随后几年Oracle 加小型机和高端存储的数据库架构支撑了淘宝网业务的爆炸式增长,数据库也从最初的两三个库增长到十几个库,并且每个库的硬件已经逐步升级到顶配,“天花板”很明显地摆在了眼前。于是在2008 年,基于PC 服务器的MySQL 数据库再次成为DBA 团队的选择,这时候MySQL 的稳定版本已经升级到5.0,并且5.1 也已经在开发中,性能和特性相对于2003 年的时候已经有了非常大的提升。淘宝网的数据库架构也逐渐从垂直拆分走向水平拆分,在大规模水平集群的架构设计中,开源的MySQL 受到的关注度越来越高,并且一年多来的实践也证明了MySQL(存储引擎主要使用的是InnoDB)在高压力下的可用性。于是从2009 年开始,后来颇受外界关注的所谓“去IOE”开始实施,经过三年多的架构改造,到2012年整个淘宝网的核心交易系统已经全部运行在基于PC 服务器的MySQL 数据库集群中,全部实例数超过2000 个。今年的“双11”大促中,MySQL 单库经受了最高达6.5 万的QPS,某个拥有32 个节点的核心集群的总QPS 则稳定在86 万以上,并且在整个大促(包括之前三年的“双11”大促)期间,数据库未发生过任何影响大促的重大故障。当然,这个结果,也得益于淘宝网整个应用架构的设计,以及这几年来革命性的闪存设备的迅猛发展。

  2008 年,淘宝DBA 团队准备从Oracle 转向MySQL 的时候,团队中的大多数人对MySQL 的了解都非常之少。当时国内技术圈对MySQL 的讨论也不多见,网上能找到的大多数中文资料基本上关注的还是如何安装,如何配置主备复制等。而MySQL 中文类的书籍,大部分还是和PHP 放在一起,作为PHP 开发中的一环来讲述的。所以当我们发现mysqlperformanceblog.com 这个相当专业的国外博客的时候,无不欣喜莫名。同时也知道了博客的作者们2008 年出版的High Performance MySQL 第二版(中文版于2010 年1 月出版),这本书被很多MySQL DBA 们奉为圭皋,书的三位主要作者Baron Schwartz、Peter Zaitsev 和Vadim Tkachenko 也在MySQL DBA 圈中耳熟能详,他们组建的Percona 公司和Percona Server 分支版本以及XtraDB 存储引擎也逐渐为国内DBA所熟知。2011 年12 月,淘宝网和O’Reilly 在北京联合举办的Velocity China 2011 技术大会上,我们有幸邀请到Percona 公司的华人专家季海东(目前已离职)来介绍MySQL 5.5 InnoDB/XtraDB 的性能优化和诊断方法。在季海东先生的引荐下,我们也和Peter 通过Skype 电话会议有过沟通,介绍了MySQL 在淘宝的应用情况,我们对MySQL 一些特性的需求,以及对MySQL 做的一些patch,并随后保持了密切的邮件联系。有了这些铺垫,我们对于在生产系统中采用Percona Server 5.5 也有了更大的信心,如今已有超过1000个Percona Server 5.5 的实例在线上运行。所以今年上半年电子工业出版社的张春雨(侠少)编辑找到我来翻译本书的第三版的时候,很是激动,一口应承。

  考虑到这么经典的书应该尽快地和读者见面,故此我邀请了团队中的MySQL 专家周振兴(花名:苏普)、彭立勋、翟卫祥(花名:印风)、刘辉(花名:希羽)一起来翻译。其中,我负责前、推荐序和第1、2、3 章,周振兴负责第5、6、7 章,彭立勋负责第4、8、9、14 章,翟卫祥负责第10、11、12、13 章,刘辉负责第15、16 章和附录部分,最后由我负责统稿。所以毫无疑问,这本书是团队合作的结晶。虽然我们满怀激情,但由于都是第一次参与翻译技术书籍,确实对困难有些预估不足,加上下半年为了准备“双11”等各种大促,需要在DBA 团队满负荷的工作间隙挤出个人时间,初稿出来后,由于每个人翻译风格不太一致,几次审稿修订,也让本书的编辑李云静和白涛吃了不少苦头,在此对大家表示深深的感谢,是大家不懈的努力,才使得本书能够顺利地和读者见面。但书中肯定还存在不少问题,也恳请读者不吝指出,欢迎大家和我的新浪微博http://weibo.com/NinGoo 进行互动。

  同时还要感谢本书第二版的译者们,他们娴熟的语言技巧给了我们很多的参考。也要感谢帮助审稿的同事们,包括但并不仅限于张新铭(花名:俊达)、张瑞(花名:张瑞)、吴学章(花名:维西)等,彭立勋甚至还发动了他女朋友加入到审稿工作中,在此一并表示感谢。当然,最后还要感谢我的妻子Lalla,在我占用了大量周末时间的时候能够给予支持,并承担了全部的家务,让我以译书为借口毫无心理负担地偷懒。

   宁海元(花名:江枫)
   2013 年3 月 于余杭

使用RPM&YUM进行基础软件管理

上周花时间研究了下RPM打包的方法,今天和团队分享了一次。之前我们采用shell脚本进行批量的MySQL安装,虽然通过不断改进的脚本,批量安装部署的效率已经算不错。但即使是安装MySQL这样简单的事情,不断提升效率,在大规模的环境中也是会带来更多的收益。

追求简单,做到极致,共勉之。

InnoDB的多版本一致性读的实现

InnoDB是支持MVCC多版本一致性读的,因此和其他实现了MVCC的系统如Oracle,PostgreSQL一样,读不会阻塞写,写也不会阻塞读。虽然同样是MVCC,各家的实现是不太一样的。Oracle通过在block头部的事务列表,和记录中的锁标志位,加上回滚段,个人认为实现上是最优雅的方式。 而PostgreSQL则更是将多个版本的数据都放在表中,而没有单独的回滚段,导致的一个结果是回滚非常快,却付出了查询性能降低的代价。

InnoDB的实现更像Oracle,同样是将数据的旧版本存放在单独的回滚段中,但是也有不同。之前还以为整体实现都会跟Oracle不会有太大的出入,也一直没有太在意去看具体实现。今晚晚上下班准备回家时,刚好路过几个同事在交流分享这个问题,遇到一个疑问:

我们知道,InnoDB表会有三个隐藏字段,6字节的DB_ROW_ID,6字节的DB_TX_ID,7字节的DB_ROLL_PTR(指向对应回滚段的地址),这个可以通过innodb monitor看到,当然如果你熟悉innodb文件结构,也可以直接od ibd文件来验证。一致性读主要跟后两者有关系。InnoDB内部维护了一个递增的tx id counter,其当前值可以通过show engine innodb status获得

echo "show engine innodb status\G" | mysql -uroot | grep "Trx id counter"

假设有一个表,当前已经有两条记录。这时候我们开始一个实验,开启两个session,A和B,都设置autocommit=0

MySQL>set global autocommit=0;

T1时间:
A开始一个事务,执行一条select,可以看到已有的两条记录,show engine innodb status可以知道A的tx id,假设为7430
T2时间:
B开始一个事务,执行一条select,可以看到已有的两条记录,可以知道B的tx id,为7431
T3时间:
A中insert一条记录,此时A再select能看到,所以返回三条记录,而B无法看到,还是返回两条记录。
T4时间:
A中执行commit提交事务,分别在A和B中select,得到的结果和T3时间相同。

Ok,假设一致性读是根据事务先后,也就是tx id来比较的话,如果B事务的一致性读是通过B的tx id即7431来和A事务中insert的这条记录的tx id即7430来比较的话,由于A.tx_id < B.tx_id,那么B应该能都到A的记录(tx id是递增的,所以越小说明事务越早开始),但如果能读到,则显然不符合多版本一致性。 因此结果是正确的,那么就是InnoDB的一致性读的实现方式不是像我们按照经验来测试的那样了。通过google和察看代码,原来InnoDB还真是有一个感觉上很山寨的设计,由于tx id是事务一开始就分配的,事务中的变化也没有记录一个类似于Oracle的SCN的逻辑时钟,于是由了如下的实现: InnoDB每个事务在开始的时候,会将当前系统中的活跃事务列表(trx_sys->trx_list)创建一个副本(read view),然后一致性读去比较记录的tx id的时候,并不是根据当前事务的tx id,而是根据read view最早一个事务的tx id(read view->up_limit_id)来做比较的,这样就能确保在事务B之前没有提交的所有事务的变更,B事务都是看不到的。当然,这里还有个小问题要处理一下,就是当前事务自身的变更还是需要看到的。

有兴趣的可以去仔细看看代码的实现,在storage/innobase/read/read0read.c中实现了创建read view的函数read_view_open_now,在storage/innobase/include/read0read.ic中实现了判断一致性读是否可见的read_view_sees_trx_id。以下代码摘自5.5.8:

UNIV_INTERN
read_view_t*
read_view_open_now(
/*===============*/
	trx_id_t	cr_trx_id,	/*!< in: trx_id of creating
					transaction, or 0 used in purge */
	mem_heap_t*	heap)		/*!< in: memory heap from which
					allocated */
{
	read_view_t*	view;
	trx_t*		trx;
	ulint		n;
	ut_ad(mutex_own(&kernel_mutex));
	view = read_view_create_low(UT_LIST_GET_LEN(trx_sys->trx_list), heap);
	view->creator_trx_id = cr_trx_id;
	view->type = VIEW_NORMAL;
	view->undo_no = 0;
	/* No future transactions should be visible in the view */
	view->low_limit_no = trx_sys->max_trx_id;
	view->low_limit_id = view->low_limit_no;
	n = 0;
	trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
	/* No active transaction should be visible, except cr_trx */
	while (trx) {
		if (trx->id != cr_trx_id
		    && (trx->conc_state == TRX_ACTIVE
			|| trx->conc_state == TRX_PREPARED)) {
			read_view_set_nth_trx_id(view, n, trx->id);
			n++;
			/* NOTE that a transaction whose trx number is <
			trx_sys->max_trx_id can still be active, if it is
			in the middle of its commit! Note that when a
			transaction starts, we initialize trx->no to
			IB_ULONGLONG_MAX. */
			if (view->low_limit_no > trx->no) {
				view->low_limit_no = trx->no;
			}
		}
		trx = UT_LIST_GET_NEXT(trx_list, trx);
	}
	view->n_trx_ids = n;
	if (n > 0) {
		/* The last active transaction has the smallest id: */
		view->up_limit_id = read_view_get_nth_trx_id(view, n - 1);
	} else {
		view->up_limit_id = view->low_limit_id;
	}
	UT_LIST_ADD_FIRST(view_list, trx_sys->view_list, view);
	return(view);
}

UNIV_INLINE
ibool
read_view_sees_trx_id(
/*==================*/
	const read_view_t*	view,	/*!< in: read view */
	trx_id_t		trx_id)	/*!< in: trx id */
{
	ulint	n_ids;
	ulint	i;
	if (trx_id < view->up_limit_id) {
		return(TRUE);
	}
	if (trx_id >= view->low_limit_id) {
		return(FALSE);
	}
	/* We go through the trx ids in the array smallest first: this order
	may save CPU time, because if there was a very long running
	transaction in the trx id array, its trx id is looked at first, and
	the first two comparisons may well decide the visibility of trx_id. */
	n_ids = view->n_trx_ids;
	for (i = 0; i < n_ids; i++) {
		trx_id_t	view_trx_id
			= read_view_get_nth_trx_id(view, n_ids - i - 1);
		if (trx_id <= view_trx_id) {
			return(trx_id != view_trx_id);
		}
	}
	return(TRUE);
}

参考:
http://dev.mysql.com/doc/refman/5.1/en/innodb-multi-versioning.html
http://wangyuanzju.blog.163.com/blog/static/130292009107101544125/
http://bbs.chinaunix.net/thread-1773206-1-1.html

无觅相关文章插件,快速提升流量