草庐IT

php - SQL 基准 : PHP ActiveRecord ORM vs. MySQL 与 CodeIgniter Active Record 与标准 PHP

coder 2023-10-21 原文

测试更新为更具可读性;全部在 100 倍的 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);
    }
}

最佳答案

因此,PHP ActiveRecord ORM 在对并发连接进行基准测试时引入如此多开销的原因是,返回的每个结果都会实例化一个新的模型对象。这是使用此 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->class->name() 负责开销,比方说,每个获取的结果大约 0.004。

您将其乘以现在的记录数,(10 条记录 = 0.04)。现在将其乘以并发连接数,比方说 100,就会出现可预见的瓶颈问题。

100 个用户(假设而言)同时访问包含 10 条记录的表需要四 (4) 秒。

此时我是否应该担心,由于该库为每条记录实例化模型类的方式,所提取的记录数量可能会导致瓶颈问题?

同样,假设正确使用 ORM,这一切都可能是假设的语音,在现实世界中可能永远不存在或存在问题。除非这些测试或结论不准确,否则我在这里尝试模拟的是 100、1,000 和 10,000 名活跃现场访问者的流量负载。

换句话说,如果我不添加其他类(class)(限制 10 个),例如,浏览类(class)页面的 10,000 名访问者是否会导致 400 秒(6.67 分钟)等待其他人离开页面?如果是这样的话,那么我将找到我自己的答案(因此写这篇文章),并将考虑寻找另一个 ORM 或根据具体情况求助于重构。

这是基准测试和模拟流量负载的最合适方法吗?

其他资源

如何使用ab工具对Apache进行压力测试 https://wiki.appnexus.com/display/documentation/How+to+Apache+Stress+Test+With+ab+Tool

关于php - SQL 基准 : PHP ActiveRecord ORM vs. MySQL 与 CodeIgniter Active Record 与标准 PHP,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13366155/

有关php - SQL 基准 : PHP ActiveRecord ORM vs. MySQL 与 CodeIgniter Active Record 与标准 PHP的更多相关文章

  1. ruby - 将 spawn() 的标准输出/标准错误重定向到 Ruby 中的字符串 - 2

    我想使用spawn(针对多个并发子进程)在Ruby中执行一个外部进程,并将标准输出或标准错误收集到一个字符串中,其方式类似于使用Python的子进程Popen.communicate()可以完成的操作。我尝试将:out/:err重定向到一个新的StringIO对象,但这会生成一个ArgumentError,并且临时重新定义$stdxxx会混淆子进程的输出。 最佳答案 如果你不喜欢popen,这是我的方法:r,w=IO.pipepid=Process.spawn(command,:out=>w,:err=>[:child,:out])

  2. ruby-on-rails - 标准化文件名的字符串,删除重音和特殊字符 - 2

    我正在尝试找到一种方法来规范化字符串以将其作为文件名传递。到目前为止我有这个:my_string.mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/n,'').downcase.gsub(/[^a-z]/,'_')但第一个问题:-字符。我猜这个方法还有更多问题。我不控制名称,名称字符串可以有重音符、空格和特殊字符。我想删除所有这些,用相应的字母('é'=>'e')替换重音符号,并将其余的替换为'_'字符。名字是这样的:“Prélèvements-常规”“健康证”...我希望它们像一个没有空格/特殊字符的文件名:“prelevements_routin

  3. 使用canal同步MySQL数据到ES - 2

    文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co

  4. Hive SQL 五大经典面试题 - 2

    目录第1题连续问题分析:解法:第2题分组问题分析:解法:第3题间隔连续问题分析:解法:第4题打折日期交叉问题分析:解法:第5题同时在线问题分析:解法:第1题连续问题如下数据为蚂蚁森林中用户领取的减少碳排放量iddtlowcarbon10012021-12-1212310022021-12-124510012021-12-134310012021-12-134510012021-12-132310022021-12-144510012021-12-1423010022021-12-154510012021-12-1523.......找出连续3天及以上减少碳排放量在100以上的用户分析:遇到这类

  5. sql - 查询忽略时间戳日期的时间范围 - 2

    我正在尝试查询我的Rails数据库(Postgres)中的购买表,我想查询时间范围。例如,我想知道在所有日期的下午2点到3点之间进行了多少次购买。此表中有一个created_at列,但我不知道如何在不搜索特定日期的情况下完成此操作。我试过:Purchases.where("created_atBETWEEN?and?",Time.now-1.hour,Time.now)但这最终只会搜索今天与那些时间的日期。 最佳答案 您需要使用PostgreSQL'sdate_part/extractfunction从created_at中提取小时

  6. ruby - 在没有基准或时间的情况下用 Ruby 测量用户时间或系统时间 - 2

    因为我现在正在做一些时间测量,我想知道是否可以在不使用Benchmark类或命令行实用程序time的情况下测量用户时间或系统时间。使用Time类只显示挂钟时间,而不显示系统和用户时间,但是我正在寻找具有相同灵active的解决方案,例如time=TimeUtility.now#somecodeuser,system,real=TimeUtility.now-time原因是我有点不喜欢Benchmark,因为它不能只返回数字(编辑:我错了-它可以。请参阅下面的答案。)。当然,我可以解析输出,但感觉不对。*NIX系统的time实用程序也应该可以解决我的问题,但我想知道是否已经在Ruby中实

  7. ruby-on-rails - 无法安装 mysql2 0.3.14 gem - 2

    我看到其他人也遇到过类似的问题,但没有一个解决方案对我有用。0.3.14gem与其他gem文件一起存在。我已经完全按照此处指示完成了所有操作:https://github.com/brianmario/mysql2.我仍然得到以下信息。我不知道为什么安装程序指示它找不到include目录,因为我已经检查过它存在。thread.h文件存在,但不在ruby​​目录中。相反,它在这里:C:\RailsInstaller\DevKit\lib\perl5\5.8\msys\CORE\我正在运行Windows7并尝试在Aptana3中构建我的Rails项目。我的Ruby是1.9.3。$gemin

  8. ruby - 如何使用 ruby​​ mysql2 执行事务 - 2

    我已经开始使用mysql2gem。我试图弄清楚一些基本的事情——其中之一是如何明确地执行事务(对于批处理操作,比如多个INSERT/UPDATE查询)。在旧的ruby-mysql中,这是我的方法:client=Mysql.real_connect(...)inserts=["INSERTINTO...","UPDATE..WHEREid=..",#etc]client.autocommit(false)inserts.eachdo|ins|beginclient.query(ins)rescue#handleerrorsorabortentirelyendendclient.commi

  9. Ruby:标准递归模式 - 2

    我经常迷上ruby​​的一件事是递归模式。例如,假设我有一个数组,它可能包含无限深度的数组作为元素。所以,例如:my_array=[1,[2,3,[4,5,[6,7]]]]我想创建一个方法,可以将数组展平为[1,2,3,4,5,6,7]。我知道.flatten可以完成这项工作,但这个问题是作为我经常遇到的递归问题的一个例子-因此我试图找到一个更可重用的解决方案。简而言之-我猜这种事情有一个标准模式,但我想不出任何特别优雅的东西。任何想法表示赞赏 最佳答案 递归是一种方法,它不依赖于语言。您在编写算法时要考虑两种情况:再次调用函数的情

  10. ruby-on-rails - 使用 Ruby 标准 Logger 每天只创建一个日志 - 2

    我正在使用ruby​​标准记录器,我想要每天轮换一次,所以在我的代码中我有:Logger.new("#{$ROOT_PATH}/log/errors.log",'daily')它运行完美,但它创建了两个文件errors.log.20130217和errors.log.20130217.1。如何强制它每天只创建一个文件? 最佳答案 您的代码对于长时间运行的应用程序是正确的。发生的事情是您在给定的一天多次运行代码。第一次运行时,Ruby会创建一个日志文件“errors.log”。当日期改变时,Ruby将文件重命名为“errors.log

随机推荐