I'm using a concrete implementation of Zend_Db_Table_Abstract:
class DB_TestClass extends Zend_Db_Table_Abstract {
protected $_name = "test.TestData";
}
If I want select all rows in the table, I seem to have one option:
$t = new DB_TestClass;
$rowset = $t->fetchAll();
This returns an instance of Zend_Db_Table_Rowset which has an iterable interface you can loop though and access each row entry as a rowClass instance:
foreach($rowset as $row) {
var_dump($row);
}
HOWEVER, the rowset has loaded every row from the database into memory(!) On small tables this is OK, but on large tables - thousands of rows, for example - it quickly exhausts the memory available to PHP and the script dies.
How can I, using Zend_Db, iterate through the result set retrieving one row from a statement handle at a time, ala mysql_fetch_assoc()? This would allow efficient access to any number of rows (thousands, millions) without using excessive memory.
Thanks in advance for any suggestions.
Then fetchAll () is not capable of what you want.
You need to use Zend_Db_Select to get all the records and then do what you've intended through the loop
$select = new Zend_Db_Select ($this->getFrontController()->getParam('bootstrap')->getResource ('Db'));
$statement = $select->from ('verses')->query ();
$statement->execute ();
while ($row = $statement->fetch ())
{
// try something like that
$db_row = new Zend_Db_Table_Row (array ('table' => $table, 'data' => $row));
$db_row->text = $db_row->text . '_';
$db_row->save ();
}
Can you please specify the purpose for fetching all the rows together? Cause if you want to do some kind of processing on all the rows in the table then you any which ways have to get all the rows in to the memory. On the other hand if you want to do something like pagination, you can always use zend_pagination object which will just fetch the limited no. of rows at one time. Or better still you can set the offset and no. of rows to be fetched in the fetchAll function itself.
Related
With php ibase, ibase_query fetches the relation, several functions can then fetch rows from that relation, but all these functions extract the next row.
In Delphi I have the ability to return to the first row (DataSet.First;) - is there any equivalent in PHP ibase?
I could of course re-query the database, but this seems a waste of resources if the original relation is still accessible.
Example code:
$table = ibase_query($sql);
$row = ibase_fetch_object($table);
while (!empty($row))
{
echo $row->ENTRYNO.'<br>';
$row = ibase_fetch_object($table);
}
//The missing functionality
$table.First;
//or maybe
$row = ibase_fetch_object($table,first);
//in which case of course the following line would be redundant
$row = ibase_fetch_object($table);
while (!empty($row))
{
//process record
$row = ibase_fetch_object($table);
}
The ibase/firebird-php driver is only able to fetch forward. If you want to consult earlier rows, you will need to store them yourself in some form, or execute the query again.
Assuming I have
$db is an instance of Zend_Db_Adapter_Abstract and
$sql = 'SELECT blah blah FROM table' will return a huge number of records.
There are two code fragments to process the returned data as follows.
// Code fragment 1 (let's call it C1).
$results = $db->fetchAll($sql);
foreach ($results as $row) {
// Process $row
}
// Code fragment 2 (let's call it C2).
$stmt = $db->query($sql);
while ($row = $stmt->fetch()) {
// Process $row
}
My understanding is that C1 will load all returned data to $results. So, a huge data is loaded to PHP memory. Below are my questions.
Does C2 load all data to PHP memory or does it process one by one like prepare/execute?
Assuming there is no other option, is C1 or C2 a better option?
Thanks!
Your hunch is correct. At least if you're using the PDO driver, ->fetch() reads the results unbuffered, whereas ->fetchAll() returns all the data in a big array.
Be aware that if you're using ->fetch(), you have to be careful about what you try to do inside your loop. You can't run additional queries on the same connection while you've still got an unbuffered result set.
So, if your plan is to update those same rows inside the loop, you'll need to find a way to delay executing the updates (by queuing then up somehow) until you've exited the loop.
To retrieve one row from the result set, use the fetch() method of the
statement object. Reference
$sql = 'SELECT blah blah FROM table';
$stmt = $db->query($sql);
while ($row = $stmt->fetch()) {
// Process $row
}
In above example $stmt = $db->query($sql); retrieved the resultset in the memory and fetch is being used to fetch the current row in the loop from the resultset, which moves the cursor to the next row until it reaches the the last row in the resultset.
To retrieve all the rows of the result set in one step, use the
fetchAll() method. This is equivalent to calling the fetch() method in
a loop and returning all the rows in an array.
$sql = 'SELECT blah blah FROM table';
$stmt = $db->query($sql);
$rows = $stmt->fetchAll();
echo $rows[0]['col1']; // The first field/column from the first row
Alternatively you can use
....
$table = new Mytable();
// Find a single row Returns a Rowset
$rows = $table->find(1234);
// Find multiple rows Also returns a Rowset
$rows = $table->find(array(1234, 5678));
Reference: Zend_Db_Table..
For more: Fetching a Row..
I think fetchAll() is faster because it retrieves all the data in one step and returns an array but consumes more memory but fetch() consumes less memory but retrieves the data one by one.
The API for fetch operations has been superseded to allow a
Zend_Db_Table_Select object to modify the query. However, the
deprecated usage of the fetchRow() and fetchAll() methods will
continue to work without modification.
More Reference: Here.
as the question states.
I have implemented a function wherein it fetches multiple rows from a database (*1) and then (*2) instantiate each row as an Object. After instantiation, the Objects are then stored into an array and then return the result to caller function and then iterates through the result array and displays each Object and add html formatting for each.
Here is the snippet of the code:
function find_all() {
//(*1) Fetch 30 comments from DB
$sql = 'SELECT * FROM comments';
$sql .= ' ORDER BY datetime DESC LIMIT 30';
return find_by_sql($sql);
}
function find_by_sql($sql='') {
global $database;
$result_set = $database->query($sql);
$object_array = array();
while($row = $database->fetch_array($result_set)) {
//(*2) Instantiate each row to a Comment object
// and then stores each comment to an object array
$object_array[] = Comment::instantiate($row);
}
return $object_array;
}
//(*3) Format and display each result.
$comments = find_all();
foreach ( $comments as $comment ) {
// Not sure if syntax is correct.. anyhow..
echo "<li>$comment->get_text()</li>";
}
However, I like the above approach since it's cleaner, easier to read, maintainable, and more OOP. But the problem is it takes a longer time to display than just simply iterating through each result than display each result once it's fetched, like so:
while ($row = mysql_fetch_array($sql)) {
echo "<li>$row['text']</li>";
}
I know the reason behind why it is slow. What I want to know is there a better way to solve the problem above?
While caching might be a good idea, it won't help because I need an updated list every time the list is fetched.
I think it can be a little faster if the script gets only the part you are interested in the result set, because fetch_array() returns 2 arrays with the same result set: associative, and numeric.
By adding MYSQLI_ASSOC (if you use mysqli): mysqli_fetch_array($result, MYSQLI_ASSOC), or try with mysql_fetch_assoc(), the script receives only the associative array.
You can test in pmpMyAdmin to see the diferences.
I'm trying to get a number of columns from a PDO resultset into seperate arrays, so resulting as such:
<?php
$query = 'SELECT col1,col2 FROM tbl_imaginary';
...
$col1 = array(col1_row1, col1_row2,...);
$col2 = array(col2_row1, col2_row2,...);
?>
I know I could loop through the resultset with fetch, but it seems more efficient to use fetchAll(PDO:FETCH_COLUMN). However, once you do this, you can't perform it again unless you perform execute() on the statement handle again. I get why, you can't empty the cookie jar and then do the same again unless you fill it up again - kind of thing. So I thought I would copy the statement handle object and fetch columns of it as such:
<?php
$sh->execute();
for ($i=0; $i<$sh->columnCount(); $i++)
{
$tmp_sh = $sh;
$output[$i] = $tmp_sh->fetchAll(PDO::FETCH_COLUMN);
}
?>
However, this, just like doing fetchAll() on the original statement handle itself, outputs only the first column and not the second.
If anyone would be so kind to explain this behaviour to me and / or suggest a solution I would be most grateful.
Thank you very much in advance for your time.
Edit: So basically I want to get 2 (or more) columns from one resultset as seperate arrays, just like you would if you would perform 2 (or more) individual queries on 1 single column. The above is mostly an explanation of how I've tried to do this so far.
Why do you need two separate arrays?
$statement = $db->prepare('SELECT col1, col2 FROM tbl_imaginary');
$statement->execute();
foreach($sth->fetchAll() as $row) {
echo $row['col1'], $row['col2'];
}
I'm implementing a memcache to cache mysql query results.
It loops through the mysql results using
while($rowP3= mysql_fetch_array($result3)) {
or it loops through the memcached results (if they are saved in memcache, and not expired) via
foreach($cch_active_users_final as $rowP3) {
How can I get it to show the right looping method based on if the memcached value exists or not. I just want it to pick the right looping method. I could just duplicate the entire while { } function with all its contents, but I don't want to repeat that huge chunk of code, just so I can change while to foreach
The logic should be something like:
(partial pseudocode)
$data = get_memcached_data('cch_active_users_final');
if (!$data) {
$query = mysql_query(..);
$data = array();
while($row = mysql_fetch_array()) {
$data[] = $row;
}
store_in_memcache('cch_active_users_final', $data);
}
// do whatever you want with $data
If I understand your question, this code doesn't make sense. After querying database comparing queried results to cached values doesn't make sense.
If the $row and $rowP3 values contain the same data, you could have whatever happends in the loops in a function, and pass the row as an argument.
You don't, you use a unified method using PDO.