前段时间看了 mysqlperformance blog 上一篇关于 filesort 的文章 ,看到 Percona 公司在招聘面试的时候常问应聘者“Explain 命令输出中的 filesort 的含义是什么”这个问题,而且基本上都得不到正确的答案,甚感奇怪。
按理这是非常基础的内容了,既然敢于去 Percona 这样高手如云的公司应聘,不应该不清楚这个问题吧。
所以我也试探性的问了 MySQL圈子 中的几位朋友这个问题,结果和 Percona 所遇到的情况基本一样,仅有 1/10 的朋友真正明白 filesort 的含义,而且给出的错误答案也都和 Percona应聘者的答案差不多:是 mysql 在进行排序的时候,临时表太大,超出 MySQL 限制,需要将数据写出到磁盘文件中进行排序,所以称之为filesort。
这个“貌似正确”的答案,大部分都是因为 “filesort” 这个词的字面含义所误导猜测出来的。看来并不仅仅只有中国人喜欢“望文生义”,老外也是一样嘛!
那 Explain 命令输出信息中的 filesort 到底是什么意思呢?其实很简单,就是告诉你 MySQL 需要进行实际的排序操作而不能通过索引获得已排序数据。
个人觉得上面的错误答案其实至少错了以下两点:
- filesort(其实就是排序) 可不一定会产生临时表哦
- filesort 与临时表数据写入磁盘是没有任何直接联系的
上面两点错误中第一点在 MySQL Performance Blog 的文章中也提到了。
实际上,在我之前的一篇文章 MySQL ORDER BY 的实现分析 中已经很清楚的分析了 MySQL 在进行排序的时候,只有当返回的数据和排序条件不在同一个表中的时候,才需要使用到临时表。
学技术,真的是要非常严谨才行,如果我们仅仅通过字面意思来猜想其含义,而不仔细阅读文档并分析实验,很多时候得到的答案可能都是错误的。
explain, filesort, MySQL, order by
今天和 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 0m0.007s
[root@dc-5 /tmp]#
[1]+ Exit 1 time ./deletetest.sh
到Master 和 Slave 两端分别检查数据,看上去很正常:
root@dc-5 : (none) 01:35:43> select count(*) from test.test;
+----------+
| count(*) |
+----------+
| 1000000|
+----------+
1 row in set (1.71 sec)
root@dc-6 : (none) 01:36:01> select count(*) from test.test;
+----------+
| count(*) |
+----------+
| 1000000|
+----------+
1 row in set (1.69 sec)
我们再将set autocommit=0拿掉试试看,也就是允许系统自动提交:
[root@dc-5 /tmp]#cat deletetest.sh
#/bin/sh
mysql -uadmin -h127.0.0.1 -pxxx -e"delete from offer1.test;"
[root@dc-5 /tmp]#time ./deletetest.sh &
[1] 6722
[root@dc-5 /tmp]#./killtest.sh
[root@dc-5 /tmp]#ERROR 1053 (08S01) at line 1: Server shutdown in progress
real 0m2.462s
user 0m0.006s
sys 0m0.007s
[1]+ Exit 1 time ./deletetest.sh
再检查 Master 和 Slave 两端的数据:
root@dc-5 : (none) 01:40:30> select count(*) from offer1.test;
+----------+
| count(*) |
+----------+
| 887377 |
+----------+
1 row in set (1.66 sec)
root@dc-6 : offer1 01:44:05> select count(*) from offer1.test;
+----------+
| count(*) |
+----------+
| 1000000|
+----------+
1 row in set (1.70 sec)
Master 和 Slave 两端数据居然出现不一致,在 Master 端已经删除掉了部分数据,在 Slave 端却没有任何变化。执行 deletetest.sh 脚本前后检查 Master 的 Binary Log(SHOW Master STATUS),没有任何变化。这个 Bug 简直是太扯淡了,数据完全没有事务完整性可言了啊。
bug, innodb, MySQL, 事务
现在通过数据的水平切分(sharding)来实现数据库 Scale Out 的解决方案受到了越来越多人的青睐,但是在切分过程中可能遇到的问题也肯定不在少数,如切分规则的设计,切分后的访问路由,切分后的主键的全局唯一等等。
这里我主要列举几个可以使用在 MySQL 数据库主键全局唯一方案及其优劣,供大家参考:
- 通过应用程序生成一个GUID,然后和数据一起插入切分后的集群。优点是维护简单,实现也容易。缺点是应用的计算成本较大,且GUID比较常,占用数据库存储空间较大,涉及到应用的开发。
- 通过独立的应用程序事先在数据库中生成一系列唯一的 ID,各应用程序通过接口或者自己去读取再和数据一起插入到切分后的集群中。优点是全局唯一主键简单,维护相对容易。缺点是实现复杂,需要应用开发。
- 通过中心数据库服务器利用数据库自身的自增类型(如 MySQL的 auto_increment 字段),或者自增对象(如 Oracle 的 Sequence)等先生成一个唯一 ID 再和数据一起插入切分后的集群。优点是?好像没有特别明显的优点。缺点是实现较为复杂,且整体可用性维系在这个中心数据库服务器上,一旦这里crash了,所有的集群都无法进行插入操作,涉及到应用开发。
- 通过集群编号加集群内的自增(auto_increment类型)两个字段共同组成唯一主键。优点是实现简单,维护也比较简单,对应用透明。缺点是引用关联操作相对比较复杂,需要两个字段,主键占用空间较大,在使用 InnoDB 的时候这一点的副作用很明显。
- 通过设置每个集群中自增 ID 起始点(auto_increment_offset),将各个集群的ID进行绝对的分段来实现全局唯一。当遇到某个集群数据增长过快后,通过命令调整下一个 ID 起始位置跳过可能存在的冲突。优点是实现简单,且比较容易根据 ID 大小直接判断出数据处在哪个集群,对应用透明。缺点是维护相对较复杂,需要高度关注各个集群 ID 增长状况。
- 通过设置每个集群中自增 ID 起始点(auto_increment_offset)以及 ID 自增步长(auto_increment_increment),让目前每个集群的起始点错开 1,步长选择大于将来基本不可能达到的切分集群数,达到将 ID 相对分段的效果来满足全局唯一的效果。优点是实现简单,后期维护简单,对应用透明。缺点是第一次设置相对较为复杂。
除了上述方案之外,各位网友如果想到什么比较巧妙的解决方案,希望能不吝分享。
auto_increment, sharding, 分布式
在 IT 行业很多工程师(尤其是很多 DBA)的心目中,都把小型机视为解决性能问题的终极武器,认为小型机的处理能力要远大于 PC Server。在几年前,可能也确实是这样。但随着近几年 X86 架构芯片技术的飞速发展,PC Server 的处理能力已经越来越强悍,不断的给我们带来惊喜。
最近几年的小型机市场,基本上被 IBM 吃掉了大部分。虽然可能并不完全是因为其 Power 芯片处理能力与其他厂商的芯片相比有优势,但其处理能力方面的优异表现确实是一个很重要的因素。所以最近几年我们一直关注着 IBM 小型机与其他主机的处理能力比较,当然比较是基于 Oracle 数据库所做的一些测试。
测试基本模型如下:
- 在待测主机上安装好 Oracle 数据库,配置足够装载下所有数据的 SGA,将 Oracle 的 Redo 日志放在内存文件系统上。然后在我们技术能力范围内对 Oracle 进行相应的调优。
- 使用我们真实的线上数据抽样(约10GB),Import 进入待测试主机上的 Oracle 数据库中。
- 通过 PL/SQL 编写出模拟我们在线业务中最为典型的事务逻辑,然后使用C++编写多线程程序作为压力测试客户端。
- 通过多台主机运行压力测试程序,平缓的给待测主机增加压力,待测主机的 CPU 利用率基本用完为止。
测试数据的收集主要通过恒定时间段的 Oracle 数据库自身性能数据采样(statspack),然后分析 statspak 中的每秒事务数。以往经验显示,基本上当客户端压力线程到达一定数量之后,处理量就比较稳定甚至下降。然后我们从中取出每秒事务数的最大值,做为该机器的处理能力分值。
这个测试模型主要消耗的资源是主机的 CPU + RAM 的能力,而且当初也得到了 IBM 实验室的人认可。
通过这几年对几种主机处理能力跟踪测试情况来看,IBM Power 芯片的优势已经越来越不明显了,甚至其 Power 5+ 芯片的处理能力已经不如某些型号的 Intel x86 芯片的处理能力了,部分主机处理能力对比数据如下:
近四五年来的测试数据:
Sun v880(4C): 160
Hp rx4640(4C): 180
Dell 6650(2C): 88(2核 CPU)
Dell 6650(4C): 155
IBM P550(4c,Power 5): 294
IBM P590(8C,Power 5): 656
去年下半年至今年的测试数据:
IBM P590(16C,Power 5+): 1200
Intel (4c, Xeon(TM)): 1210 (于去年下半年发布的6核 CPU)
Intel (2c, Xeon(R)): 1107 (将于本月底发布的4核 Nehalem CPU,X5560)
从上面的数据中大家应该可以基本的了解到目前使用 Intel x86 架构的 Xeon CPU 的 PC Server 的处理能力了吧。当然,有些人可能会说,IBM Power 6 的处理能力与 Power 5 和 Power 5+ 相比有了一个较大的提升,事实如何我目前还不太清楚。但即使是其处理能力翻一倍,那也才与现在的 Nehalem 处理能力相当。
至于 PC Server 和 小型机在成本方面,这里就不多说了,我想大家都很清楚二者完全不在一个数量级上,甚至是相差两个数量级
。
可能有些人又会说,小型机在 HA 方面比 PC Server 要强。确实,这一点我是承认的,小型机的可靠性在一定程度上要比 PC Server 是要好一些,大部分设备出现故障后都不用停机即可在线更换。但随着分布式架构的不断成熟,通过架构来解决整体可用性的成功案例已经越来越多。现在该是我们转换思路的时候了!
Update on 20090318:增加最新的 IBM Power6芯片测试结果,以及每单个核的能力平均值列表
2005年:
Sun : v880,4cpu :160,平均单核40
Hp: rx464, 4cpu :180,平均单核45
dell 6650 2cpu : 88,平均单核44
dell 6650 4cpu : 155,平均单核38.75
IBM P550 4cpu : 294,平均单核73.5
IBM P590 8CPU : 656,平均单核82
2008年:
ibm p590 16 cpu: 1200,平均单核75
2009年:
intel nehalem样机, 2 cpu(每cpu 4core,X5560, 2.80GHz ) : 1107,平均单核138
IBM P550 power6 3503 MHz 4cpu: 421事务/秒,平均单核105(比08年测试 P590 提升40%)
IBM, Intel, oracle, performance, Server, 架构
今天在网上搜索资料,在百度中搜索了一个 MySQL Order By,居然发现我的一篇分析 MySQL Order By 实现原理的文章 “MySQL Order By 的实现分析” 居然排名第一,有点惊喜加意外啊,如图:

后来又尝试了一下 MySQL Group By,居然又是我的一篇分i析 MySQL Group By 实现原理的文章 “MySQL 中 GROUP BY 基本实现原理”,有点兴奋啊,如图:

再来一个 MySQL Replication,这次带来的不是兴奋了,而是很不爽。为啥?因为排名第一的仍然是我的一篇文章“MySQL Replication(复制)基本原理”,但是其他人转载,点开来一看,居然没有任何原作者信息和原文链接地址
,如图:

自己写的文章能被大家认可并转载,本是一件值得开心让人欣慰的事情,可看到没有任何说明及链接信息,心里还是很不是滋味。
group by, order by, 百度