ORM 查询结果:数组与迭代器接口中包装的结果句柄
好的,这是一个针对专业人士的:
几年来,我一直致力于自己的 PHP ORM/ActiveRecord 实现,我将其命名为 Pork.dbObject。
它大致基于我们几年前看过的电影“5 分钟内用 Rails 创建自己的网站”。 您可以执行以下操作:
$clients = dbObject::Search("Client", array("ID > 500"));
or
$client = new Client(218); // fetch row with id 218 from client table
or
$projects = $client->Find('Project');
这将从数据库中获取一行或多行,将它们包装在 dbObject 中并将它们返回到一个数组中,或者返回 false 表示没有结果。
所有这些都在数十个站点和后端中完美运行,但现在我的同事正在使用它来创建一个巨大的日志解析器,并且这里开始出现内存使用问题。
他运行的查询可以返回超过 20,000 行,甚至可能更多,这一次性包装到对象包装器中并作为单个数组返回当然不是一件好事。
显而易见的解决方案是返回一个实现 Iterator 接口的对象而不是数组。 它不应该立即从结果集中获取所有记录,而只是保存生成的数据库查询的结果资源,并在像数组一样遍历对象时在内部使用 mysql_fetch_* 。
现在我们来回答我真正的问题: 我可以毫无问题地这样做吗? 数据库是否能够处理多个打开的结果集,并将它们混合并在内存中保留一段时间?
例如,获取 20 个对象,循环它们,让这 20 个对象中的每一个获取其他 5 个对象,这反过来又获取其他 3 个对象。 这将创建一个循环,其中许多不同的结果句柄将保存在内存中。
我知道我无法序列化这些对象之一,但是我能够在 PHP5 中实现这一点而不会出现任何问题,还是数据库接口会给我带来问题?
Okay, here's one for the pro's:
For a couple of years now, i've been working on my own PHP ORM/ActiveRecord implementation that i named Pork.dbObject.
It's loosly based on the 'make your own site with rails in 5 minutes' movie we all saw a couple of years ago. You can do things like:
$clients = dbObject::Search("Client", array("ID > 500"));
or
$client = new Client(218); // fetch row with id 218 from client table
or
$projects = $client->Find('Project');
This will fetch one or more rows from the database, wrap them in a dbObject and return them in one array, or return false of there are no results.
All of this has been working perfectly in dozens of sites and backends, but now my colleague is using it to create a huge logparser and here starts the memory usage problems..
The queries he runs can return over 20.000 rows, maybe even more, which is ofcourse not a very good thing to wrap into an object wrapper all at once and return as a single array.
The obvious solution would be to return an object that implements the Iterator interface instead of an array. It shouldn't instantly fetch all the records from the resultset, but just hold the result resource for the generated database query and use mysql_fetch_* internally when you traverse the object as if it was an array.
Now we get to my real question:
Can I, without any problems just do this? Are databases able to handle multiple open resultsets, and mix them and keep them in memory for a while?
For example, fetch 20 objects, loop them, let each of these 20 fetch 5 others, wich in their turn also fetch 3 others. This would create a loop where a number of different result handles will be kept in memory.
I know i can't serialize one of these objects, but will i be able to implement this without any problems in PHP5, or will database interfaces give me problems?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这取决于您使用的数据库以及您的数据库配置。
对于 MySQL,您需要确保使用缓冲查询。 在 PDO 中,您可以这样设置:
这意味着所有数据都将发送到客户端(与在 PHP 中获取所有数据不同)。
另一种(可能更糟糕)的替代方法是,每当您检测到正在运行的查询且结果集仍然打开时,就打开一个新的数据库连接。
正常的
mysql_query()
使用缓冲查询,因此可以使用多个结果集。It depends on which database you're using and your database configuration.
For MySQL you need to make sure you use buffered queries. In PDO you set it like this:
This means that all the data will be sent to the client (not the same as fetching it all in PHP).
The other (probably worse) alternative is to open a new database connection whenever you detect a query being run with a result set still open.
The normal
mysql_query()
uses a buffered query, so that will work with multiple result sets.