-
-
Notifications
You must be signed in to change notification settings - Fork 6.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
support for fetching Query results in batches #2409
Conversation
This implementation does not allow re-using the Query object for different queries but I really like the idea! :) Needs some adjustments for reusing Query, have not checked how, yet. |
$this->_dataReader = $this->createCommand($db)->query(); | ||
} | ||
$count = 0; | ||
$results = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$results
-> $result
@cebe you mean the scenario, when not all results are read from the cursor, the query is altered and another call to I don't like tracking the dataReader as a protected var but I want to keep it simple. What about passing it as an argument instead the $db? Then the developer would be responsible for tracking the dataReader and closing the cursor manually if not all results are read. |
It looks great to me. Yes, I have the same concern about having How about the following syntax? foreach (Post::find()->with('author')->batch(10) as $posts) {
// $posts is an array with maximum length 10
} The method |
such feature is in L4, can look how it is done there, but they make simple wrapper. |
Can't find it. What is its syntax? |
|
It seems to be based on limit/offset, which we want to avoid as discussed in #2387. |
@qiangxue I like the iterator idea but in case of @Ragazzo I also like the |
ok, i think this can be an extension
yeah, can you point to sentence about not using |
@nineinchnick Yes, we need to turn some private method into public in Regarding the collection idea, we have discussed about it at the very beginning when we were designing Yii2 AR. Our conclusion was to keep things simple, at least for 2.0. You may go ahead and create a ticket about this. In the ticket, we would like to see every possible use case example of the collection so that we have better understanding of the requirements. |
to be true, i dont think there will be a lot of use-cases, main of them is to not consume a lot of memory, for example when exproting to pdf/excel. So there will not be a lot of use-cases. Worth creating ticket? |
@Ragazzo yes. It's requested quite often but use cases aren't clear each time so it definitely needs a good separate discussion. |
Done - #2423. Feel free to add your use-cases and delete here comments to not to mess them with main discussion here. |
Just FYI, I'm working on this currently. will finish soon. |
Is it finished? I haven't seen a relevant commit. I've been working on this too. |
Not committed yet. Almost finished. Writing documentation now. |
Will let you know. Please help review my change. Sorry, I should let you know earlier. |
Great) |
Done (api doc to be finished). For the usage, please see: Please help review the code. Your feedback is very welcome. Thanks. |
Looks fine to me, docs are good, have not tried it yet though. Also want to note that for implementing such feature there was added not so much code, that is because of great Yii2 AR design. |
Thank you for your comments and review. All work are done. |
First I have to say I am impressed how great the AR design works and how extensible it is with different features :-) usage: foreach($query->batch(10) as $user) {
// $user will be one single instance
} This way the BatchQueryResult will only hold the datareader and will load next batch when I iterate over the size of the batch. This would be more like what I would expect from this method to do. Otherwise I would need nested foreach to handle all users in DB: foreach($query->batch(10) as $users) {
foreach($users as $user) {
// $user will be one single instance here
}
} This approach would also make it simpler to switch from: foreach($query->all() as $user) { //... to: foreach($query->batch(10) as $user) { //... This would make the iterator implementation a bit more complicated but in general more easy to use interface. |
@cebe: the reason for this design is to support some functions or handlers that can handle a batch of data each time. For example, foreach ($query->batch(10) as $users) {
$handler->handle($users);
} Otherwise, batch size 10 and batch size 1 really don't differ much. If you want to get one user a time, you can use foreach ($query->each() as $user) {
} |
okay, makes sense. |
Well... thinking a bit more about it this behavior is still bad for AR because of relational queries. each() should still be able to fetch a batch internally and populate relations for a number of records. |
I agree. |
You are right. 'Each' also needs batch size. Will fix it. On Saturday, February 15, 2014, Jan Waś notifications@github.com wrote:
|
Done: 9a068f5 |
I have a problem when using this: It started to work after I added this: There must be some mistake or I do something wrong? |
Fixed. Thanks! |
Resolves #2387 by adding the ability to process Query results in batches.
This PR introduces a
next()
method in db\Query and db\ActiveQuery, which is a wrapper over db\DataProvider. DataProvider can't be used directly, because in ActiveQuery private methods are used to perform lazy loading.Executing following code, when there are 4 users:
results in having the following queries:
Should other Query implementations also introduce such method? Probably not if there's no cursor available thus there's no gain in batch processing.