When running a long query from PHP, [how] can I kill the query if the user presses stop in their browser?
Take into consideration that I cannot call
PHP, in most cases, won't know that a connection was closed (since the user aborted) until it tries to send something over the network and then receives a SIGPIPE. The only thing you can do is try working with timeouts aborting to long queries or killing them from another process.
This is an example of doing it with PDO.
$id = $connection->executeQuery("SELECT CONNECTION_ID()")->fetchColumn();
ignore_user_abort(true);
while($row = $result->fetch()) {
/* Processing ... */
if (connection_aborted()) {
$this->connection->executeQuery("KILL CONNECTION $id");
break;
}
}
Note: Keep an eye out for multiple connections, you may kill the wrong one.
i think you can give a try to mysql KILL
http://dev.mysql.com/doc/refman/5.0/en/kill.html
if you are able to call something over user abort then you can use KILL
to kill you mysql connection or query by fetching it's process id.
And as you said in your comment that PHP is blocked until mysql returns
so you can take help from javascript in this way:
1.detect the user abort using JS 2.call a function on user abort 3.in that function you can kill you previous query but here you need the process id of the previous query so you can get that by a trick that you can select the process id when you run you first long query and pass it to JS function and use it in killing you query.
Hope it will help you.
Once PHP notices the user has stopped the request (this usually will not happen until the script tries to output something to the user), your script will terminate. Before shutting down, PHP calls any shutdown functions you've activated. You can implement a shutdown function that kills your query, and register it with register_shutdown_function()
An other way you might be able to do this, is by running your script with ignore_user_abort() turned on, and checking if the user has aborted by calling connection_aborted() periodically. If the user has aborted, kill the query and gracefully exit your script.
More information on connection handling here.
For those who are interested, here is what I used:
<?php
// Connection to query on
$query_con = mysqli_connect($host, $user, $password, $name, $port);
// Connection to kill on
$kill_con = mysqli_connect($host, $user, $password, $name, $port);
// Start the query
$query_con->query($slow_query, MYSQLI_ASYNC);
// Get the PID
$thread_id = $query_con->thread_id;
// Ignore user abort so we can kill the query
ignore_user_abort(true);
do {
// Poll MySQL
$links = $errors = $reject = array($mysqli->mysqli);
$poll = mysqli_poll($links, $errors, $reject, 0, 500000);
// Check if the connection is aborted and the query was killed
if (connection_aborted() && mysqli_kill($kill_con, $thread_id)) {
die();
}
} while (!$poll);
// Not aborted, so do stuff with the result
$result = $link->reap_async_query();
if (is_object($result)) {
// Select
while ($row = $result->fetch_object()) {
var_dump($row);
}
} else {
// Insert/update/delete
var_dump($result);
}
If the time taken by query is because of the large dataset returned, then you can use mysql_unbuffered_query
. And then in shutdown_function
you can free the result and disconnect form mysql.
And if you are using PHP 5.3.x and have mysqlnd
you can probably use MYSQLI_ASYNC
in mysqli_query and then use mysqli_poll
to get the result.
The first option will only help in case of time taken in retrieval of dataset. But if the mysql is actually taking a long time in parsing and creating the execution plan and loading tables to memory it wont help. In that case you need MYSQLI_ASYNC
which is only available on PHP 5.3.x
WITH mysqlnd
.
Also if your main problem is session locking
have a look at this post on PHP's documentation http://php.net/manual/en/ref.session.php#64525
You might find some helpful advice there.