《MySQL性能调优与架构设计》开始正式发售
Friday, June 12th, 2009
今天,公元2009年06月11日,本人第一本独立完成的原创技术书籍《MySQL性能调优与架构设计》开始在China-Pub 上正式首发了,卓越购买地址:《MySQL性能调优与架构设计》。
很多朋友问我写书的感觉是怎样的,说实话,只需要一个字就可以形容:“累”。从开始写这本书到现在,已经将近一年没有看过电视,每天下班后就开始写,每天晚上都要到12点之后,周六周日都是如此。从那时候开始,我就再也没有看过电视了。
当然,写完之后,还是有较大的成就感的。不管最后各位读者朋友的评价如何,都是倾注了自己这段时间来所有的心血。而且在整个过程中,对自己的知识技能也有很大的提高,包括知识体系的整合,细节的进一步理解。
第一次写书,没有任何经验,又是一个人独自完成,由于实在太辛苦,中途甚至有一次差点决定放弃,幸好自己毅力还算坚定,最后总算坚持下来了。现在回头想想,不禁有点佩服自己的毅力。
一个人的能力毕竟有限,书中肯定会存在不少问题,还请读者朋友们能够指出,万分感谢!
出自:Sky.Jian 朝阳的天空 《MySQL性能调优与架构设计》正式发售
MySQL内存使用-线程独享
Monday, April 20th, 2009
对于任何一个数据库管理系统来说,内存的分配使用绝对可以算的上是其核心之一了,所以很多希望更为深入了解某数据库管理系统的人,都会希望一窥究竟,我也不例外。
从内存的使用方式MySQL 数据库的内存使用主要分为以下两类
线程独享内存
全局共享内存
今天这篇文章暂时先分析 MySQL 中主要的 “线程独享内存” 的。
在 MySQL 中,线程独享内存主要用于各客户端连接线程存储各种操作的独享数据,如线程栈信息,分组排序操作,数据读写缓冲,结果集暂存等等,而且大多数可以通过相关参数来控制内存的使用量。
线程栈信息使用内存(thread_stack):主要用来存放每一个线程自身的标识信息,如线程id,线程运行时基本信息等等,我们可以通过 thread_stack 参数来设置为每一个线程栈分配多大的内存。
排序使用内存(sort_buffer_size):MySQL 用此内存区域进行排序操作(filesort),完成客户端的排序请求。当我们设置的排序区缓存大小无法满足排序实际所需内存的时候,MySQL 会将数据写入磁盘文件来完成排序。由于磁盘和内存的读写性能完全不在一个数量级,所以sort_buffer_size参数对排序操作的性能影响绝对不可 小视。排序操作的实现原理请参考:MySQL Order By 的实现分析。
Join操作使用内存(join_buffer_size):应用程序经常会出现一些两表(或多表)Join的 操作需求,MySQL在完成某些 Join 需求的时候(all/index join),为了减少参与Join的“被驱动表”的读取次数以提高性能,需要使用到 Join Buffer 来协助完成 Join操作(具体 Join 实现算法请参考:MySQL 中的 Join 基本实现原理)。 当 Join Buffer 太小,MySQL 不会将该 Buffer 存入磁盘文件,而是先将Join Buffer中的结果集与需要 Join 的表进行 Join 操作,然后清空 Join Buffer 中的数据,继续将剩余的结果集写入此 Buffer 中,如此往复。这势必会造成被驱动表需要被多次读取,成倍增加 IO 访问,降低效率。
顺序读取数据缓冲区使用内存(read_buffer_size):这部分内存主要用于当需要顺序读取数据的时 候,如无发使用索引的情况下的全表扫描,全索引扫描等。在这种时候,MySQL 按照数据的存储顺序依次读取数据块,每次读取的数据快首先会暂存在read_buffer_size中,当 buffer 空间被写满或者全部数据读取结束后,再将buffer中的数据返回给上层调用者,以提高效率。
随机读取数据缓冲区使用内存(read_rnd_buffer_size):和顺序读取相对应,当 MySQL 进行非顺序读取(随机读取)数据块的时候,会利用这个缓冲区暂存读取的数据。如根据索引信息读取表数据,根据排序后的结果集与表进行Join等等。总的来 说,就是当数据块的读取需要满足一定的顺序的情况下,MySQL [...]
MySQL 5.1 中 Innodb 的事务完整性Bug
Tuesday, March 17th, 2009
今天和 51.com 的 MySQL DBA 景春同学一起遇到了个 MySQL 非常扯淡的Bug:在 5.1 版本中,Innodb 存储引擎如果使用autocommit=0的情况下,单条SQL在执行过程中如果异常中断的话,事务完整性可能无法保证,不论是STATEMENT还是 MIXED的binlog_format,都存在相同的问题,可以重现,屡试不爽。
测试环境如下:
OS:SunOS 5.10 Generic_137138-09
DB:MySQL 5.1.31/32-log Source distribution
binlog_format:MIXED/STATEMENT
tx_isolation:REPEATABLE-READ
测试脚本如下:
[root@dc-5 /tmp]#cat deletetest.sh
#/bin/sh
mysql -uadmin -h127.0.0.1 -pxxx -e”set autocommit=0;delete from test.test;”
[root@dc-5 /tmp]#cat killtest.sh
#/bin/sh
mysqladmin -uroot processlist |grep “admin”|awk ‘{print $2}’|xargs mysqladmin -uroot kill
将删除的脚本放到后台执行,然后执行kill脚本:
[root@dc-5 /tmp]#time ./deletetest.sh &
[1] 6708
[root@dc-5 /tmp]#./killtest.sh
ERROR 1053 (08S01) at line 1: Server shutdown in progress
real 0m2.901s
user 0m0.007s
sys [...]
MySQL 5.1.31 发布
Sunday, February 8th, 2009
MySQL 从去年11月底发布了 5.1 的 GA 版本(5.1.30)之后,业内对其产品质量出现了大量的质疑声。估计 SUN 为此也头疼了不少时日吧,对产品质量的改进肯定也是加紧进行了。这不,才过去两个来月的时间,又发布了新的一版 5.1.31。
在刚刚发布的 5.1.31 版本中主要做了以下的改进:
功能增加或改进:
新增状态变量 Queries ,和原 Questions 的区别在于除了包含 Questions 已经包含的所有计数之外,还增加了存储过程中所执行的 Query。
select * from information_schema.column 语句的性能改进
全文索引增加 Hint 支持(如:ignore index(ft_index_name) 等)
Bug fixed:
(bug 40116),解决了当一个 定义在 Innodb 上面的 Trigger 更新非事务表数据的时候,可能出现事务未提交前就已经被 Replicated 到Slave 端并且能够被访问的问题。
(bug 39084),在复制 Innodb 的分区表的时候,如果更改事务隔离级别,可能出现基于语句(Statement)的二进制日志记录失败的现象。
(bug 40972),当一个非法日期类型数据(date或者datetime)出现在 WHERE 条件中查询分区表的时候,可能造成 mysqld crash。
(bug 40595),在 READ COMMITED 事务隔离级别下,Innodb 的一致读功能有时会出现异常,但是在分区表上又正常。
… …
除了上面的这些 Bug 之外,还有大量的 Bug 都已经被 fix [...]
MySQL 图书目前写作进度
Friday, January 16th, 2009
从开始撰写这本关于 MySQL 数据库系统性能调优及架构设计的图书到现在已经5个月时间了,从最初到现在,即使连初稿都没有完成,就已经修改过多次。包括提纲内容,章节调整删减等等。
期间收到过很多朋友的建议与意见,都对我有很大的帮助,在此表示真诚的感谢!
明天就要回家休假了,到时候可能会有一段时间不会上网,不过大家放心,仍然会坚持写作。在回家之前将目前的进度大体说一下:
第一篇基础篇基本完成,但有一幅非常重要的图暂时还没有画;
第二篇维护篇完成70%,暂停写作;
第三篇优化篇完成95%,待整合修整;
第四篇架构篇完成50%,正在进行中;
注:以上所有内容目前还处于比较粗糙的初稿阶段
考虑到受众对象对内容的期望以及网友相关建议,经过和出版社商量,有可能会对第一篇和第二篇做一些调整,合为一篇,但目前还并没有确定,如果各位朋友有任何建议和意见,随时可以 Mail 反馈给我 sky000 [AT] gmail.com。
再次感谢各位朋友给我提出的很多宝贵建议以及对我的支持,谢谢!
作者:Sky.Jian | 可以任意转载, 但转载时务必以超链接形式标明文章原始出处 和 作者信息 及 版权声明
链接:http://www.jianzhaoyang.com/life-tips/mysql-performance-architechture-schedule-now
MySQL DISTINCT 的基本实现原理
Friday, December 12th, 2008
接上一篇: MySQL 中 GROUP BY 基本实现原理
DISTINCT 实际上和 GROUP BY 操作的实现非常相似,只不过是在 GROUP BY 之后的每组中只取出一条记录而已。所以,DISTINCT 的实现和 GROUP BY 的实现也基本差不多,没有太大的区别。同样可以通过松散索引扫描或者是紧凑索引扫描来实现,当然,在无法仅仅使用索引即能完成 DISTINCT 的时候,MySQL 只能通过临时表来完成。但是,和 GROUP BY 有一点差别的是,DISTINCT 并不需要进行排序。也就是说,在仅仅只是 DISTINCT 操作的 Query 如果无法仅仅利用索引完成操作的时候,MySQL 会利用临时表来做一次数据的“缓存”,但是不会对临时表中的数据进行 filesort 操作。当然,如果我们在进行 DISTINCT 的时候还使用了 GROUP BY 并进行了分组,并使用了类似于 MAX 之类的聚合函数操作,就无法避免 filesort 了。
下面我们就通过几个简单的 Query 示例来展示一下 DISTINCT 的实现。
1.首先看看通过松散索引扫描完成 DISTINCT 的操作:
sky@localhost : example 11:03:41> EXPLAIN SELECT DISTINCT group_id
-> FROM group_message\G
*************************** [...]
MySQL 中 GROUP BY 基本实现原理
Tuesday, December 9th, 2008
之前连着写了几篇关于 MySQL 中常用操作的一些基本实现原理,如,MySQL ORDER BY,MySQL Join,这次再写一篇 MySQL 中 GROUP BY 的基本实现原理。
由于 GROUP BY 实际上也同样会进行排序操作,而且与 ORDER BY 相比,GROUP BY 主要只是多了排序之后的分组操作。当然,如果在分组的时候还使用了其他的一些聚合函数,那么还需要一些聚合函数的计算。所以,在GROUP BY 的实现过程中,与 ORDER BY 一样也可以利用到索引。
在 MySQL 中,GROUP BY 的实现同样有多种(三种)方式,其中有两种方式会利用现有的索引信息来完成 GROUP BY,另外一种为完全无法使用索引的场景下使用。下面我们分别针对这三种实现方式做一个分析。
1.使用松散(Loose)索引扫描实现 GROUP BY
何谓松散索引扫描实现 GROUP BY 呢?实际上就是当 MySQL 完全利用索引扫描来实现 GROUP BY 的时候,并不需要扫描所有满足条件的索引键即可完成操作得出结果。
下面我们通过一个示例来描述松散索引扫描实现 GROUP BY,在示例之前我们需要首先调整一下 group_message 表的索引,将 gmt_create 字段添加到 group_id 和 user_id 字段的索引中:
sky@localhost : example 08:49:45> create index [...]
MySQL 中 Join 的基本实现原理
Thursday, December 4th, 2008
在 MySQL 中,只有一种 Join 算法,就是大名鼎鼎的 Nested Loop Join,他没有其他很多数据库所提供的 Hash Join,也没有 Sort Merge Join。顾名思义,Nested Loop Join 实际上就是通过驱动表的结果集作为循环基础数据,然后一条一条的通过该结果集中的数据作为过滤条件到下一个表中查询数据,然后合并结果。如果还有第三个参 与 Join,则再通过前两个表的 Join 结果集作为循环基础数据,再一次通过循环查询条件到第三个表中查询数据,如此往复。
还是通过示例和图解来说明吧,后面将通过我个人数据库测试环境中的一个 example(自行设计,非MySQL 自己提供) 数据库中的三个表的 Join 查询来进行示例。
注意:由于这里有些内容需要在MySQL 5.1.18之后的版本中才会体现出来,所以本测试的MySQL 版本为5.1.26
表结构:
sky@localhost : example 11:09:32> show create table user_group\G
*************************** 1. row ***************************
Table: user_group
Create Table: CREATE TABLE `user_group` (
`user_id` int(11) NOT NULL,
`group_id` int(11) NOT NULL,
`user_type` int(11) NOT NULL,
`gmt_create` datetime NOT NULL,
`gmt_modified` [...]


