更新的测试更具可读性;所有这些都在100x foreach循环中完成。
测试查询为 SELECT * FROM school_courses;
任何人都可以提供“开箱即用”的反馈意见:
a)为什么PHP ActiveRecord ORM需要4秒才能按照以下结果执行相同的查询?
b)这是一个实用的基准还是更多用于比较查询方法的假设基准?
c)是否有其他方法(测试用例)我应该尝试(或修改这些方法)以获得更清晰的图像?
结果(使用PDO和MySQLi)
Iterations: 100
PHP (config file)
Base Time: 5.793571472168E-5
Gross Time: 0.055607080459595
Net Time: 0.055549144744873
PHP ActiveRecord ORM
Base Time: 5.2213668823242E-5
Gross Time: 4.1013090610504
Net Time: 4.1012568473816
MySQL (standard)
Base Time: 5.1975250244141E-5
Gross Time: 0.32771301269531
Net Time: 0.32766103744507
CodeIgniter (Active Record)
Base Time: 5.1975250244141E-5
Gross Time: 0.28282189369202
Net Time: 0.28276991844177
MySQLi
Base Time: 5.1975250244141E-5
Gross Time: 0.20240592956543
Net Time: 0.20235395431519
PDO
Base Time: 5.2928924560547E-5
Gross Time: 0.17662906646729
Net Time: 0.17657613754272
测试
// Benchmark tests
$runs = 100;
// PHP (config file)
for ($i = 0; $i < $runs; $i++) {
$this->view_data['courses'] = course_info();
}
// PHP ActiveRecord ORM
for ($i = 0; $i < $runs; $i++) {
$this->view_data['courses'] = Course::all();
}
// mysql_* (MySQL standard; deprecated)
for ($i = 0; $i < $runs; $i++) {
$sql = mysql_query('SELECT * FROM school_courses') or die(mysql_error());
while ($row = mysql_fetch_object($sql)) {
array_push($this->view_data['courses'], $row);
}
}
// CodeIgniter (Active Record)
for ($i = 0; $i < $runs; $i++) {
$this->view_data['courses'] = $this->db->get('school_courses');
}
// mysqli_* (MySQLi)
for ($i = 0; $i < $runs; $i++) {
$res = $mysqli->query('SELECT * FROM school_courses');
while ($row = $res->fetch_object()) {
array_push($this->view_data['courses'], $row);
}
}
// PDO
for ($i = 0; $i < $runs; $i++) {
foreach($conn->query('SELECT * FROM school_courses') as $row) {
array_push($this->view_data['courses'], $row);
}
}
答案 0 :(得分:2)
因此,在对并发连接进行基准测试时,PHP ActiveRecord ORM引入如此多开销的原因是由于返回的每个结果都实例化了一个新的Model对象。这对于使用这个ORM库是不可或缺的,我没有看到任何合理的方法在不对整个库进行大修的情况下进行更改。
这是我发现的:
在Table类的find_by_sql()方法中,您有:
$sth = $this->conn->query($sql,$this->process_data($values));
while (($row = $sth->fetch()))
{
$model = new $this->class->name($row,false,true,false);
if ($readonly)
$model->readonly();
if ($collect_attrs_for_includes)
$attrs[] = $model->attributes();
$list[] = $model;
}
具体来说,动态模型实例化 new $ this-&gt; class-&gt; name()负责开销,在每个结果的大约0.004左右称重,比如说。
你取此并乘以现在的记录数,(10条记录= 0.04)。现在将它乘以并发连接的数量,假设为100,并且您有可预见的瓶颈问题。
100个用户(假设说)同时访问包含10条记录的表格的四(4)秒。
此时我是否应该担心,由于此库为每条记录实例化一个模型类的方式,所提取的记录数可能会导致瓶颈问题?
同样,这一切都可能是此时假设的演讲,假设正确使用ORM,可能永远不存在或在现实世界中出现问题。除非这些测试或结论不准确,否则我在这里要模拟的是100,1,000和10,000名活跃的现场访问者的流量负载。
换句话说,如果我没有添加另一个课程(限制10),例如,浏览课程页面的10,000名访问者将导致其他人离开页面的400秒(6.67分钟)等待时间?如果是这种情况,那么我将发现我自己的答案(因此这篇文章),并将研究寻找另一个ORM或诉诸于逐案重构。
这是基准测试和模拟流量负载的最合适方式吗?
其他资源
如何使用ab工具进行Apache压力测试 https://wiki.appnexus.com/display/documentation/How+to+Apache+Stress+Test+With+ab+Tool
答案 1 :(得分:1)
重写推荐:
我不想听起来很残酷,但如果你忘记了所有关于mysql_()的知识,你可以在将来节省很多头痛,并跟上当前的做法。按照今天的标准,老实说它是垃圾。查看mysqli_或PDO作为数据库接口。
mysqli_:http://us2.php.net/manual/en/book.mysqli.php
PDO:http://us2.php.net/manual/en/book.pdo.php
然后报告基准......
答案 2 :(得分:0)
您的简单查询并不是真正的公平测试。对于那样的简单查询,ORM很好并且相当有竞争力。它是更复杂的(即LEFT JOIN),ORM创建低效的查询,你最终不得不绕过它们。 ORM总是比知道SQL的人编写的原始SQL慢。当然,了解SQL是关键。
如果你正在考虑ORM,你真的应该尝试Doctrine。我不是粉丝ORMs(根本没有),但那是最受欢迎的PHP ORM。
批量插入也是一些ORM和DB抽象层绊倒的另一个领域。它们不是认识到可以使用批量插入,而是在循环中进行单个插入。除了速度慢之外,这将导致MyISAM上的表锁定问题。也许添加批量插入测试,让每个数据库层尽可能生成插入查询。
您的测试方法所揭示的是,在多次迭代中,每种数据库访问方法的开销都会增加。我建议完全消除查询开销,而只是使用“SELECT VERSION()”。