红豆 ORM 性能

21

我想知道Redbean ORM是否可以用于性能导向的场景,如社交网络Web应用程序等。如果多个用户同时拉取数千个数据,它是否稳定。此外,我想知道Redbean是否会消耗更多的内存空间。

是否有人可以提供Doctrine-Propel-Redbean的比较研究?


在任何情况下,编写纯 SQL 将为您提供更优化的代码。如果您关心性能,那么请放弃 ORM 思想。 - tereško
@tereško 如果可能的话,您能否根据您的经验列出ORM相对于纯SQL的优缺点,并且我也会同时在谷歌上搜索这个主题。 - Jaison Justus
4个回答

66

我认为 Tereško 的回答并不完全正确。

首先,它没有解决原问题。这确实是反ORM的一个案例,我同意他在回答中描述的问题。这就是为什么我写了 RedBeanPHP。只是因为大多数ORM无法使你的生活变得更容易,这并不意味着对象关系映射系统的概念有缺陷。大多数ORM试图隐藏SQL,这就是为什么JOIN变得如此复杂的原因;它们需要在面向对象的环境中重新发明类似的东西。这就是 RedBeanPHP 的不同之处,因为它不隐藏SQL。它创建可查询的可读、有效的SQL表格。RedBeanPHP 使用普通的SQL进行记录和bean检索,而不是虚构的查询语言。简而言之,RedBeanPHP 与SQL共同工作,而不是相互对立。这使它变得不那么复杂。

是的,RedBeanPHP 的性能很好。我怎么这么肯定?因为与其他ORM不同,RedBeanPHP区分开发模式和生产模式。在开发周期中,数据库是流动的;您可以添加条目,并且它们将被动态添加。RedBeanPHP 创建列、索引、猜测数据类型等。甚至在一段时间后,如果需要更多字节(更高的数据类型),它也可以拉伸列。这使得 RedBeanPHP 在开发时间极其缓慢,但速度不应是一个问题。完成开发后,使用单个模式指定器 R::freeze() 冻结数据库,不再进行任何检查。您所剩下的就是在生产服务器上的一个非常简单的数据库层。因为没有做太多事情,所以性能很好。

是的,我知道,我是RedBeanPHP的作者,所以我有偏见。然而,我觉得我的ORM被视为其他ORM一样,这促使我写这篇文章。如果您想了解更多信息,请随时参考RedBeanPHP网站,这里是关于性能的讨论

在我们公司,我们在嵌入式系统和金融业务系统中使用RedBeanPHP,所以它似乎相当可扩展。

我和RedBeanPHP社区一起真诚地努力使ORM世界变得更好;你可以在这里阅读任务声明。

祝你的项目好运,希望你找到你要寻找的技术解决方案。


RedBeanPHP缺少对表前缀的支持,这是一个丑陋的特性,但仍然被广泛使用。此外,它也没有完全集成,因为可链接的查询不直接返回ORM对象列表。你需要明确调用R::convertToBeans来实现。 - Phillip Whelan
@halfer,这个问题已经在邮件列表上出现,并因性能原因以及为了支持RedBeanPHP 3中的一些新功能而被否决。虽然理论上我可以同意这一点,但实际工作的真正本质并不总是允许这样做。 - Phillip Whelan
2
我刚刚放弃了Doctrine2,因为它在执行复杂查询时失败了,并开始尝试使用RedBeanPHP。到目前为止,我喜欢RedBean的地方在于你不必远离SQL查询。我不喜欢的是它缺乏表前缀支持和命名规则 - 我更喜欢编写表名order_detail或OrderDetail而不是orderdetail,但也许这只是我的个人偏好。 - jaycode
哦,而且redbeanphp的命名规范非常棒!Doctrine强制你映射表中的每个字段,这太糟糕了。 - jaycode
如何在Memcached中使用RedBeanPHP?感谢Gabor创建RedBean! - Steven
显示剩余2条评论

37

@tereško如果可能的话,您能根据您的经验列出ORM相对于纯SQL的优缺点吗?同时我也会在谷歌上搜索这个主题。- Jaison Justus

嗯...用600个字符来解释这个问题很难。

我必须澄清一件事:这是关于PHP中的ORMs,虽然我很确定它也适用于某些Ruby ORMs和其他一些ORMs。

简而言之,你应该避免使用ORMs,但是如果你必须使用ORM,则最好选择Doctrine 2.x,它是较小的邪恶。(实现了类似于DataMapper而不是ActiveRecord的东西)。

反对ORMs的情况

一些开发人员喜欢使用ORMs的主要原因也是它们最糟糕的地方:在ORM中执行简单操作很容易,性能成本非常低。这完全没问题。

1. 指数复杂度

问题源于人们将同一工具用于所有事情。这导致创建technical debt

起初编写新的数据库相关代码很容易。也许,因为你有一个大项目,在前几周管理层决定雇用更多人员(因为后来会引起其他问题——如果对细节感兴趣,请阅读神话般的人月。最终,你会更喜欢具有ORM技能而不是一般SQL的人。
但是,随着项目的进展,你将开始使用ORM来解决日益复杂的问题。你将开始绕过某些限制,并最终可能会遇到一些无法通过所有已知的ORM黑客解决的问题……现在你没有SQL专家,因为你没有雇用他们。
此外,大多数流行的ORM都实现了ActiveRecord,这意味着你的应用程序业务逻辑直接与ORM耦合。由于这种耦合,添加新功能将需要越来越多的时间。同样的原因,很难为它们编写好的单元测试。 2. 性能 我已经提到,即使是ORM的简单用法(仅涉及单个表格,无连接),也有一些性能成本。这是因为它们使用通配符*来选择数据。当你只需要文章ID和标题列表时,获取内容就没有意义。
ORM在处理多个表格时非常糟糕,当你需要基于多个条件获取数据时。考虑以下问题:
数据库包含4个表:Projects、Presentations、Slides和Bulletpoints。
- Projects有很多Presentations。 - Presentations有很多Slides。 - Slides有很多Bulletpoints。
您需要从与ID为2、4和8的Projects相关的最新4个Presentations中标记为“important”的所有Slides中找到所有Bulletpoints的内容。这是一个在纯SQL中编写的简单JOIN,但在我看过的任何ORM实现中,这将导致三级嵌套循环,并在每个级别上进行查询。

附言:还有其他原因和副作用,但它们相对较小...现在无法记起任何其他重要问题。


4
顺便提一下:这篇文章讨论了关于“对象-关系映射是计算机科学中的越南战争”的话题。 - tereško
4
@JaisonJustus,顺便提一下,“BTW”是“顺带一提”的缩写。 - tereško
4
我明白你的观点,但我认为这不是不使用ORM的理由。就像你所说,你只需要雇佣一些SQL专家,并确保用纯SQL编写复杂查询。ORM并不会取代SQL。问题在于在哪里使用ORM和哪里使用SQL,但相信我,如果你的页面变慢了,你会想到如何解决。非常感谢你的好回答! - PiTheNumber
2
@PhillipWhelan,嗯... Kohana的“ORM”更像是一个光荣的查询构建器而不是ORM。当你需要进行复杂的请求时,你最终会将纯SQL 1:1翻译成kORM-ized方法调用,这将使其变回SQL。你最终只是掩盖了你的查询,并在此过程中失去了对结果SQL的控制。 - tereško
5
ORM(对象关系映射)对于快速开发很有帮助。如果你的查询很复杂,就用简单的SQL语句来写。我会混合使用这两种方式。 - Shiplu Mokaddim
显示剩余8条评论

22

我在这里与 @tereško 不同 - ORM 可以使数据库查询更容易编写和维护。在我的观点中,Propel 和 Doctrine 都有一些出色的工作 - 请利用它们!网络上有很多性能比较,并且也要检查 NotORM(我没有使用过,但如果我记得正确,它们进行了一些和 Doctrine 的比较)。

如果你到达一个需要使用原始SQL的吞吐量点,那么在那个时候进行优化。但是从减少错误数量和提高生产效率的角度来看,我认为你的节省会为更好的服务器提供资金。当然,你的收益可能因情况而异。

顺便说一下,我不认识 RedBean,但我觉得 Propel 在大多数情况下比 Doctrine 更快,因为类是预先生成的。当 Propel 是唯一的选择时,我使用了它,并坚持使用它,尽管我肯定不排斥使用 Doctrine。

2018 更新

经过多年开发,Propel 2 仍处于 alpha 版本,需要进行多项重大重构项目,但遗憾的是,这些项目并未得到解决。虽然维护者称此 alpha 版本具有良好的测试覆盖率,可以在生产中使用,但他们现在已经开始开发 Propel 3。不幸的是,在我撰写本文时,这个版本尚未发布,尽管代码库已经一岁了。

虽然我认为 Propel 是一个很棒的项目,但我想暂时最好使用其他东西。它可能会再次崛起!


如果使用ORM从数据库中检索超过1000条记录,会消耗更多的空间吗?我认为ORM的输出很可能是对象数组形式。 - Jaison Justus
3
一般来说,无论使用哪种ORM,都应该警惕在内存中保存大量行的情况。虽然这个数量在离线处理中听起来不错,但对于Web请求来说就不够了。相反地,你应该分批进行:比如每次选择50个元素,做20个选择;这样可以降低内存使用率。或者,如果这只是你应用程序的一小部分,你可以通过原始的数据库调用(通过ORM来保持数据库独立性)来完成这部分工作。最后(最好的方法),看看能否将这个任务移动到离线处理中。 - halfer
我应该提到ORM可以让你轻松地做一些像嵌套集这样的事情,或者实现各种行为(例如可版本化、时间戳、可存档)。或者,如果你有一个主/从数据库配置,一些ORM将使用循环方式将写操作发送到一个数据库并从多个数据库读取 - 只需设置一个配置值即可。 - halfer
3
谷歌搜索“propel without pear”?有很多结果,包括我博客上的一个 :). 编辑:不要在ORM系统之间花费太多时间做决策。选择一个你“喜欢”的并开始使用。在你现在还没有用户的系统和未来可能达到Facebook规模的系统之间,你很可能会重写两到三次。先让它工作起来。 - halfer
1
由于我的博客似乎已经从谷歌搜索结果中消失了(呃),我所提到的文章在这里(http://blog.jondh.me.uk/2011/02/some-pointers-on-propel-1-5/)。虽然是针对1.5版本的,但在1.6上应该也能正常使用。 - halfer
显示剩余6条评论

10

我会选择“因地制宜”的做法,采用两个世界的混合搭配。我使用RedBean构建了一些大型应用程序,因此我的评论将纯粹集中在RedBean上,而不是其他ORM。

RedBean ORM速度慢吗?

这取决于你如何使用它。在某些情况下,它比传统查询更快,因为RedBean会缓存结果几秒钟。重复使用查询将产生更快的结果。查看日志使用R::debug(true);它总是显示:

"SELECT * FROM `table` -- keep-cache"

场景1:获取全部数据(*)

在RedBean中,如果您进行查询:

$result = R::findOne('table', ' id = ?', array($id));

这被表示为

$result= mysql_query("Select * from TABLE where id =".$id);

你可能会争辩说,如果这个表有多列,为什么你要查询(*)

情景2:单列

获取单列数据

R::getCol( 'SELECT first_name FROM accounts' );

就像我提到的“因地制宜”,开发人员不应只依赖于FindOne、FindAll、FindFirst、FindLast,而应该仔细草拟他们真正需要的内容。

场景3:缓存

当您不需要缓存时,可以在应用程序级别禁用缓存,但这并不是理想的情况。

R::$writer->setUseCache(true);

RedBean建议,如果您不想在应用程序级别禁用缓存,则应使用传统查询来获取没有缓存参数的结果,如$result = R::exec("SELECT SQL_NO_CACHE * FROM TABLE");

这完美地解决了从表中提取实时数据的问题,通过完全丢弃查询缓存。

场景4:快速开发

使用ORM使您的应用程序开发非常快速,开发人员可以使用ORM编码比编写SQL快2-3倍。

场景5:复杂查询和关系

RedBean提供了一种实现复杂查询和一对多多对多关系的非常好的方法。

使用纯SQL进行复杂查询

$books = R::getAll( 'SELECT 
    book.title AS title, 
    author.name AS author, 
    GROUP_CONCAT(category.name) AS categories FROM book
    JOIN author ON author.id = book.author_id
    LEFT JOIN book_category ON book_category.book_id = book.id
    LEFT JOIN category ON book_category.category_id = category.id 
    GROUP BY book.id
    ' );
    foreach( $books as $book ) {
        echo $book['title'];
        echo $book['author'];
        echo $book['categories'];
    }

OR RedBean处理多对多关系的方式

list($vase, $lamp) = R::dispense('product', 2);

$tag = R::dispense( 'tag' );
$tag->name = 'Art Deco';

//creates product_tag table!
$vase->sharedTagList[] = $tag;
$lamp->sharedTagList[] = $tag;
R::storeAll( [$vase, $lamp] );

性能问题

通常类似ORM这样的参数会使得应用程序变慢、消耗更多内存。但我认为这种情况不适用于RedBean。

我们已经在MySQL和Postgres上进行了测试,相信我,性能从来都不是瓶颈。

毋庸置疑,ORM会增加一些开销并会使得应用程序变慢(只是一点点)。使用ORM主要是为了在开发时间和轻微降低运行时性能之间进行权衡。我的策略是首先使用ORM构建应用程序,然后根据测试用例调整关键速度模块以使用直接数据访问。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接