You are NOT required to read all rows from the resultset when using unbuffered query, you may opt out at any time and use mysql_free_result. Imagine looking at 1 million row when the first 50 suffice? Just free the result and you are good to go again.
mysql_unbuffered_query
(PHP 4 >= 4.0.6, PHP 5)
mysql_unbuffered_query — Envía una consulta SQL a MySQL, sin recuperar ni colocar en búfer las filas de resultado
Descripción
$query
[, resource $link_identifier = NULL
] )
mysql_unbuffered_query() envía la query SQL a MySQL,
sin recuperar ni colocar en búfer las filas de resultado automáticamente, como
mysql_query() lo hace. Por una parte, esto ahorra una considerable
cantidad de memoria con las consultas SQL que producen conjuntos grandes de resultados
y se puede empezar a trabajar con el conjunto de resultado inmediatamente después de que la
primera fila ha sido recuperada: no necesita esperar hasta que la consulta SQL completa
haya sido ejecutada. Para usar mysql_unbuffered_query() cuando se usan
múltiples conexiones con la BD, se necesita indicar el parámetro opcional
link_identifier para identificar que conexión se desea
utilizar.
Parámetros
-
query -
La consulta SQL a ejecutar.
Los datos dentro del query deben estar propiamente escapados.
-
link_identifier -
La conexión MySQL. Si el identificador de enlace no se especifica, el último enlace abierto por mysql_connect() es asumido. Si no se encuentra dicho enlace, la función intentará establecer un nuevo enlace como si mysql_connect() fuese invocado sin parámetros. Si no se encuentra o establece una conexión, un error de nivel
E_WARNINGes generado.
Valores devueltos
Para sentencias SELECT, SHOW, DESCRIBE o EXPLAIN,
mysql_unbuffered_query() devuelve un valor
resource en caso de éxito, o FALSE si ocurre
un error.
Para otro tipo de sentencias SQL, UPDATE, DELETE, DROP, etc,
mysql_unbuffered_query() devuelve TRUE en caso
de éxito o FALSE si ocurre un error.
Notas
Nota:
Los beneficios de mysql_unbuffered_query() tienen un precio: No se puede usar mysql_num_rows() ni mysql_data_seek() en un conjunto de resultados devuelto por mysql_unbuffered_query(), hasta que todas las filas sean recuperadas. También se tendrá que recuperar todas las filas de resultado de una consulta SQL sin búfer antes de poder enviar una nueva consulta SQL a MySQL, usando el mismo
link_identifier.
Note: The benefits of mysql_unbuffered_query() come at a cost: You cannot use mysql_num_rows() and...
but it looks like you can use SQL_CALC_ROWS on MySQL to get the total rows without the limit.
If you use mysql_ping() to check the connection, the resultset from mysql_unbuffered_query() will be kill.
If you are going to do a large query, but are concerned about blocking access to the table during an unbuffered query, why not go through a temporary table? (Of course, this is predicated on the current user having permission to create tables.)
<?php
$dbQuery = "SELECT something ...";
if (mysql_query ("CREATE TEMPORARY TABLE MyQuery $dbQuery")) {
$numRows = mysql_affected_rows();
if ($numRows == 0) {
/* handle empty selection */
} else {
$result = mysql_unbuffered_query ('SELECT * FROM MyQuery');
/* handle result */
}
mysql_query ('DROP TABLE MyQuery');
}
?>
If using optimized MyISAM tables I guess there is a big advantage with this function as it is possible to do selects and inserts on the same time as long as no rows in the table gets updated.
The other hand should really be, that the table remains locked until all rows have been retrieved, right? This is a very important thing to mention, you could tie up the whole database with a lock.
Regarding bailing on a really large result, while doing an unbuffered query, there _is_ a way to do this: kill the thread and exit your processing loop. This, of course, requires having a separate database link. Something like below does the trick:
<?php
// a db link for queries
$lh = mysql_connect( 'server', 'uname', 'pword' );
// and a controller link
$clh = mysql_connect( 'server', 'uname', 'pword', true );
if ( mysql_select_db ( 'big_database', $lh ) )
{
$began = time();
$tout = 60 * 5; // five minute limit
$qry = "SELECT * FROM my_bigass_table";
$rh = mysql_unbuffered_query( $qry, $lh );
$thread = mysql_thread_id ( $lh );
while ( $res = mysql_fetch_row( $rh ) )
{
/* do what you need to do
* ...
* ...
*/
if ( ( time() - $began ) > $tout )
{
// this is taking too long
mysql_query( "KILL $thread", $clh );
break;
}
}
}
?>
Don't let the two hands confuse you, these are both advantages (they should really be on the same hand):
On the one hand, this saves a considerable amount of memory with SQL queries that produce large result sets.
On the other hand, you can start working on the result set immediately ...
You are absolutely required to retrieve all rows in the result set (option 'a' in the first comment). If you fail to do so, PHP will do so for you, and will emit a NOTICE warning you of the fact. From the MySQL API, "Furthermore, you must retrieve all the rows even if you determine in mid-retrieval that you've found the information you were looking for. ".
Also note that if you are using this function, you should be quick about processing the result set, or you will tie up the MySQL server (other threads will be unable to write to the tables you are reading from).
If you want to be able to 'abort' mid result-set or if you want to do lengthy processing on the results, you are misunderstanding the purpose of this function.
Also note that UPDATE queries etc return no result set, so this function is only useful for SELECT etc.
