Java、PHP、Python与MySQL交互的性能测试

这几天看源码弄清了一件事:WEB服务器接收浏览器请求、将请求传给PHP/Python进程(FCGI等)、与数据库进行交互都是用socket(套接字)。

也就是说,这些行为都是进程间通信。一台WEB服务器在硬件、操作系统不变的情况下,它的性能主要取决于socket通信的速度。如果所有进程都在一台服务器上的话,这个速度就取决于通信的效率了。

例如与MySQL数据库交互时,程序会调用驱动程序来访问数据库,这个驱动程序主要做这几件事:

 1.创建socket,连接到MySQL。
2.将程序调用的API翻译成SQL语句,通过socket发送给MySQL;MySQL执行后,将结果发送回来;驱动程序将结果(字符串)传给程序,如有需要,还可以自动翻译成程序能识别的变量类型(如整型)。
3.断开连接。

可见连接的速度、翻译的速度和接受响应的及时性是最主要的3个方面。

 弄明白这点后就不难发现,与数据库的执行时间相比,这些只是很少的一部分;而且PHP和Python使用的都是C实现,而JDBC是用Java实现,所以根本不必担心PHP和Python的性能。不过在翻译方面还存在算法和实现上的差异,客户端还可以缓存一些语句,所以仍然会出现一些性能上的差异。为证明我的想法,我特意去测试了一番。

首先列出测试平台:

  • CPU:Intel Core2 Duo T9400 @ 2.53GHz
  • 内存:3GB
  • 操作系统:Windows XP Pro SP2
  • MySQL:5.1.36
  • Java:1.6.0_17-b04
  • JDBC:MySQL Connector/J 5.1.10
  • PHP:5.2.11 (cli)
  • MySQLi:5.2.11.11
  • Python:2.6.4
  • MySQL-Python:1.2.3c1

 

所用的库都是最新版的,也都采用了最为推荐的库。
但数据库并没有使用最新的稳定版,因为我懒得重下了。5.4.3-beta测试版也试过,在连续插入时,性能比5.1快1~2个数量级,估计是服务器端缓存和设置的原因。

测试项目:

  • 创建100万个随机数,并生成插入这些随机数的SQL语句。
  • 连接本地数据库,如不成功,尝试创建数据库。
  • 删除并创建数据库表,引擎类型为InnoDB,主键为自动递增的整数,此外有个浮点型的字段(无索引)。
  • 分成100组,每次插入1万个随机数。(因为每组的执行量都很大,因此启用自动提交事务。)
  • 用SELECT COUNT(*)统计小于0.1的随机数个数。(约10万个)
  • 用SELECT *取出再统计大于0.9的随机数个数。(约10万个)
  • 将所有0.4~0.5之间的随机数加1。(约10万个)
  • 将所有0.5~0.6之间的行删除。(约20万个)
  • 断开数据库连接。
  • 再次连接数据库。

每种测试3次(等硬盘灯无闪烁后才进行下一次测试),取最好的一次作为测试结果:

java:

  • 测试数据量:1000000
  • 测试引擎:InnoDB
  • 共有99465个小于0.1的随机数
  • 共有99859个大于0.9的随机数
  • 创建随机数:2.367840
  • 初次连接数据库:0.220420
  • 再次连接数据库:0.013174
  • 初始化数据库和表:0.075140
  • 插入:12.139346
  • 选择(COUNT):1.130345
  • 选择:1.017769
  • 更新:6.173245
  • 删除:9.380070
  • 关闭连接:0.002131
  • 总时间:32.506307

php:

  • 测试数据量:1000000
  • 测试引擎:InnoDB
  • 共有99898个小于0.1的随机数
  • 共有100152个大于0.9的随机数
  • 创建随机数:1.506294
  • 初次连接数据库:0.003146
  • 再次连接数据库:0.001808
  • 初始化数据库和表:0.131754
  • 插入:12.046944
  • 选择(COUNT):1.236742
  • 选择:1.238153
  • 更新:6.115232
  • 删除:8.145547
  • 关闭连接:0.000125
  • 总时间:30.423937

Python(MySQLdb):

  • 测试数据量: 1000000
  • 测试引擎: InnoDB
  • 共有100040个小于0.1的随机数
  • 共有100351个大于0.9的随机数
  • 创建随机数: 1.6822107279
  • 初次连接数据库: 0.0332120423126
  • 再次连接数据库: 0.00221704155137
  • 初始化数据库: 0.131054924578
  • 插入: 11.7999030603
  • 选择(COUNT) 1.27067266929
  • 选择: 1.16714526567
  • 更新: 6.29200638629
  • 删除: 8.13660563005
  • 关闭连接: 0.000131022238861
  • 总时间: 30.5129417286

Python(_mysql):

  • 测试数据量: 1000000
  • 测试引擎: InnoDB
  • 共有99745个小于0.1的随机数
  • 共有99869个大于0.9的随机数
  • 创建随机数: 1.68099074044
  • 初次连接数据库: 0.0112056141213
  • 再次连接数据库: 0.00159293988482
  • 初始化数据库: 0.130169616529
  • 插入: 12.1364623157
  • 选择(COUNT) 1.125517908
  • 选择: 0.968366649951
  • 更新: 6.8042843434
  • 删除: 8.9760508668
  • 关闭连接: 9.61015995031e-05
  • 总时间: 31.8331441566

可以看到,在大批量数据测试中,Java是最慢的,而PHP是最快的。
不考虑IO性能的波动的话,Java主要慢在连接和关闭数据库。JDBC 4.0在第一次连接数据库时会动态加载驱动,非常耗时,因此使用Java要记住使用数据库连接池,避免连接浪费大量时间。当然,这也造成了数据库的负担,势必影响内存占用。而创建随机数的算法实现各不相同,所以不具备可比性;令我惊讶的是SELECT的翻译速度,将字符串转换成浮点数居然慢于Python,要知道后者的浮点数可是对象。
PHP连接数据库非常快,所以完全无需使用连接池,因为维护连接池会增加复杂性。
Python的表现和PHP差不多,但是第一次连接数据库比较慢(仍比Java快1个数量级)。如果不用连接池,则使用FCGI等方式来运行比较合适。_mysql模块的通信很快,但更新和删除操作却不太理想,也许是IO性能波动的原因。此外,我在连接数据库时使用了转换参数,实际上我用的语句都不需要翻译,不使用的话会更快一点。

接着试试小数据,改成最常用的MyISAM引擎,插入100条(1组)。一般的应用不可能一次插入那么多,所以足够满足平时的应用了;而且由于数据量很小,也基本不受IO影响。

测试结果:

java:

  • 测试数据量:100
  • 测试引擎:MyISAM
  • 共有9个小于0.1的随机数
  • 共有10个大于0.9的随机数
  • 创建随机数:0.001596
  • 初次连接数据库:0.224135
  • 再次连接数据库:0.018656
  • 初始化数据库和表:0.055601
  • 插入:0.001476
  • 选择(COUNT):0.000529
  • 选择:0.000433
  • 更新:0.000304
  • 删除:0.000313
  • 关闭连接:0.000927
  • 总时间:0.285314

PHP:

  • 测试数据量:测试数据量:100
  • 测试引擎:MyISAM
  • 共有12个小于0.1的随机数
  • 共有9个大于0.9的随机数
  • 创建随机数:0.000649
  • 初次连接数据库:0.008077
  • 再次连接数据库:0.001609
  • 初始化数据库和表:0.060421
  • 插入:0.001860
  • 选择(COUNT):0.000580
  • 选择:0.000465
  • 更新:0.000326
  • 删除:0.000373
  • 关闭连接:0.000127
  • 总时间:0.072878

 

Python(MySQLdb):

  • 测试数据量: 100
  • 测试引擎: MyISAM
  • 共有14个小于0.1的随机数
  • 共有9个大于0.9的随机数
  • 创建随机数: 0.000198907961766
  • 初次连接数据库: 0.0334640296462
  • 再次连接数据库: 0.00150577796899
  • 初始化数据库: 0.0123194428342
  • 插入: 0.00125211444471
  • 选择(COUNT) 0.000581079438867
  • 选择: 0.000484139744018
  • 更新: 0.000250311142897
  • 删除: 0.000262323842835
  • 关闭连接: 7.98984228442e-05
  • 总时间: 0.0488922474784

 

Python(_mysql):

  • 测试数据量: 100
  • 测试引擎: MyISAM
  • 共有12个小于0.1的随机数
  • 共有10个大于0.9的随机数
  • 创建随机数: 0.000214273043082
  • 初次连接数据库: 0.0118774872225
  • 再次连接数据库: 0.00123702872851
  • 初始化数据库: 0.0315031659052
  • 插入: 0.00120322554962
  • 选择(COUNT) 0.000596165155069
  • 选择: 0.000507327048549
  • 更新: 0.0002447238406
  • 删除: 0.00026148574749
  • 关闭连接: 5.78285787719e-05
  • 总时间: 0.0464656820909

 

从结果可以看出,虽然差距都很小,但Python仍然稍微占优。不过Java的SELECT操作稍微胜出,而这也是实际应用中最常使用的操作。

再从语言方面来看,Python无疑是写得最欢畅的,生成随机数只用了1行代码;PHP的变量要写个$让我老是出错,不过数据库操作不需要处理异常,这点节省了很多代码;Java的代码量很大,而且不得不使用很多try...catch,我甚至懒得以安全的方式将close()放在finally块里面,因为它也会抛出我根本懒得去管的异常,且会提示我计时变量可能没有初始化。

总体上来看,Google放弃Python,只采用C++和Java是有点不明智。因为页面响应时间主要在于数据库通信和磁盘文件IO上,语言的影响基本忽略不计。

本文转自keakon的blog 原文地址:http://www.keakon.cn/bbs/thread-1858-1-1.html

WordPress啦的评论:

长知识了!!!!

发表评论:

网站分类

最新评论及回复

文章归档