How to limit execution time in MySQL? - mysql

I have following code to limit execution time in MySQL but it is not working.
Someone help me out.
delimiter //
CREATE PROCEDURE `classicWatches`.kill_long_running_queries()
BEGIN
DECLARE process_id BIGINT;
DECLARE finished INT DEFAULT 0;
DECLARE kill_process_id CURSOR FOR SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND = 'Query' AND TIME > 5; # only for 5 seconds just testing whether it works or not
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
OPEN kill_process_query;
loop_loop: LOOP
FETCH kill_process_id INTO process_id;
IF process_id >=1 THEN
KILL QUERY process_id ; # Here showing error in mysql workbench but don't know what error
END IF ;
IF finished THEN
LEAVE loop_loop;
END IF;
END LOOP loop_loop;
CLOSE kill_process_id;
END //
delimiter ;
CREATE EVENT kill_long_running_queries
ON SCHEDULE EVERY 10 SECOND
DO CALL `classicWatches`.kill_long_running_queries();

I'm not quite sure what you want to accomplish.
The error shown in Workbench is because an integer is expected (as shown on line 23 - line 23 is just an example), but it is found process_id variable, however, the stored procedure is created and executed correctly when invoked.
The cursor is kill_process_id, but on line 13 you open the cursor kill_process_query does not exist, you need to change for line 14.

Related

mysql: retry transaction specified number of times

I have an sql script which deletes large number of records from database. Script deletes records by small chunks:
DROP PROCEDURE IF EXISTS `my_proc`;
DELIMITER $$
CREATE PROCEDURE my_proc()
BEGIN
DECLARE chunk_size INT DEFAULT 1000;
main: LOOP
SET #count= -1;
START TRANSACTION;
DELETE FROM my_table WHERE .... LIMIT chunk_size;
SELECT ROW_COUNT() into #count;
COMMIT;
IF #count = 0 THEN
LEAVE main;
END IF;
DO SLEEP(0.1);
END LOOP main;
END$$
DELIMITER ;
CALL my_proc();
DROP PROCEDURE IF EXISTS `my_proc`;
The problem is that DELETE statement may fail, so I want retry deletion of current chunk 10 times. So I want the script to fail only if the DELETE statement fails 10 times for current chunk.
I try to use DECLARE CONTINUE HANDLER FOR 1213 BEGIN ..... END; but do not quite understand how to make it work. The main problem now is to make the script fail with meaningful (preferably original) error message if the DELETE failed 10 times.

How to troubleshoot MySQL procedure - Why loop is reaching max runs?

I have MySQL stored procedure that will create temporary table from remote server using FEDERATED tables. Then the procedure used these temporary table to do some work.
I am seeing some issue where I get an error like
Unable to connect to foreign data source
Got timeout reading communication packets
Unable to connect to foreign data source
Got error 1430 from storage engine
The problem here is that if these temporary table failed to create the entire procedure fails because the tables do not exists.
So I thought I can do some checking after the attempt to create temporary table and if the attempt return error then I go back and try it again. to stop an infinite loop I added a condition to quite after 10 tries.
The issue that i am running into is that the script quits and it does not run all the way to the end.
here is a portion of the procedure where the procedure is quitting and not sure why.
DELIMITER $$
CREATE DEFINER=`root`#`10.%` PROCEDURE `act`()
MAIN:
BEGIN
DECLARE current_procedure_name CHAR(60) DEFAULT 'activities';
DECLARE last_run_time DATETIME DEFAULT NULL;
DECLARE current_run_time_start DATETIME DEFAULT NOW();
-- set the SQL mode to ''
SET SQL_MODE = '';
-- set MySQL Safe mode OFF on update
SET SQL_SAFE_UPDATES = 0;
SET #trys = 0;
loop_label: LOOP
SET #trys := #trys+1;
-- db.view_users is a federated table
DROP TEMPORARY TABLE IF EXISTS view_users1, view_users2, view_users3;
CREATE TEMPORARY TABLE view_users1 (KEY(user_id)) ENGINE=MEMORY AS
SELECT user_id, fullname
FROM db.view_users;
IF(##error_count > 0 OR #trys > 10) THEN
-- if there are too many tries to create the temporary table and it keeps failing Quit!!
IF( #trys > 10) THEN
LEAVE MAIN;
ELSE
-- sleep for 10 seconds and go back to create the table again
SELECT SLEEP(10);
ITERATE loop_label;
END IF;
END IF;
CREATE TEMPORARY TABLE view_users2 (KEY(user_id)) ENGINE=MEMORY AS
SELECT * FROM view_users1;
IF(##error_count > 0) THEN
ITERATE loop_label;
END IF;
CREATE TEMPORARY TABLE view_users3 (KEY(user_id)) ENGINE=MEMORY AS
SELECT * FROM view_users1;
IF(##error_count > 0) THEN
ITERATE loop_label;
END IF;
END LOOP;
-- set MySQL Safe mode back ON on update
SET SQL_SAFE_UPDATES = 1;
END
How can I find out why it is quitting? it seem that #trys is reaching 11 and it quits but I don't understand why would it?
I have tried to run this code outside the procedure and the second line returns 0 error;
DROP TEMPORARY TABLE IF EXISTS view_users1, view_users2, view_users3;
CREATE TEMPORARY TABLE view_users1 (KEY(user_id)) ENGINE=MEMORY AS
SELECT user_id, fullname
FROM db.view_users;
SELECT ##error_count;
A second question, is there a better approach for this problem? it is important that this procedure runs all the way.
I finally figure out the cause of the issue.
from the manual 13.6.5.5 LOOP Syntax
The statements within the loop are repeated until the loop is
terminated. Usually, this is accomplished with a LEAVE statement.
Within a stored function, RETURN can also be used, which exits the
function entirely
at the end just before END LOOP; I needed to add LEAVE loop_label to end the LOOP other wise it will continue until #trys reaches 11;

mysql stored proc is not working from mysqlworkbench or java code

I have written a stored proc in mysql when i am running it through hopper it is working fine but when i am trying to run it from mysql workbench or java it is not returning any result and also not showing any exception
I will request you to please help me on this
-- --------------------------------------------------------------------------------
-- Routine DDL
-- Note: comments before and after the routine body will not be stored by the server
-- --------------------------------------------------------------------------------
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `issueitem`()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE inventoryids INT DEFAULT 0;
DECLARE batch varchar(39);
DECLARE resultstr varchar(3000) DEFAULT '';
DECLARE exp DATE;
DECLARE mfgdate DATE;
DECLARE availableunit INT;
DECLARE quantity INT DEFAULT 100;
DECLARE oldest_date DATETIME;
DECLARE cur_count INT;
DECLARE que_size INT DEFAULT 0;
DECLARE curs CURSOR FOR SELECT inventoryid,batch,exp,availableunit FROM aashramdata.inventory where itemid=1 ORDER BY exp ASC;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN curs;
SET cur_count=quantity;
read_loop: LOOP
FETCH curs INTO inventoryids,batch,exp,availableunit;
IF done THEN
LEAVE read_loop;
END IF;
SET que_size = que_size + availableunit;
IF cur_count >= availableunit THEN
set cur_count=cur_count-availableunit;
set resultstr=CONCAT(resultstr,batch,' - ',exp,' - ',availableunit,' - ');
update aashramdata.inventory set `availableunit`=0 where inventoryid=inventoryids;
END IF;
IF cur_count < availableunit THEN
update aashramdata.inventory set `availableunit`=availableunit-cur_count where inventoryid=inventoryids;
set resultstr=CONCAT(resultstr,batch,' - ',exp,' - ',availableunit-cur_count,' - ');
set cur_count=0;
END IF;
IF que_size >= quantity then
LEAVE read_loop;
END IF;
END LOOP;
CLOSE curs;
select resultstr;
END
Since the procedure is apparently syntactically valid, it's impossible to answer what the problem might be, without some knowledge of the data.
The easiest way to debug a stored procedure is by peppering it with unbounded SELECT statements (that is, selects that are not part of a subquery and not part of an INSERT ... SELECT or SELECT ... INTO) and then running it from the MySQL command line client, which handles multiple result sets from stored procedures much more gracefully than most graphical clients.
For example:
...
SET cur_count=quantity;
SELECT cur_count; -- add this
read_loop: LOOP
FETCH curs INTO inventoryids,batch,exp,availableunit;
SELECT inventoryids,batch,exp,availableunit; -- add this
SELECT done; -- add this
IF done THEN
...
When run from the command line client...
mysql> CALL issueitem();
...output will start rolling out of the console at you, showing you the internal values the procedure is encountering as it iterates the loop.
This, or other SELECT statements like this added elsewhere, will expose the internal variables and this should help you find the problem. You'll need to remove them before you call the procedure from code or even the GUI since the GUI may not handle them well -- it may start opening new tabs or splitting panes or just ignoring everything after the first SELECT.
Note that the last iteration of the loop, you may see the values from the previous iteration repeated since the failed read from the cursor may not reset the variables, but "done" will also transition from 0 to 1 indicating that the cursor has run out of rows and fired the CONTINUE HANDLER, so those values won't actually have been processed twice.

MySQL - detecting and handling Lock Wait Timeout inside Stored Procedure

The Question
purely for academic reasons, I'm wondering if you could add a handler to a mysql stored procedure that is able to recover from a lock wait timeout error if one of its queries locks up (such as a SELECT ... FOR UPDATE or UPDATE) query.
The Example
This is assuming an innoDB database, set to issolation level Repeatable read, with an empty users table defined.
1. Example Procedure:
DROP PROCEDURE IF EXISTS `lock_test`;
DELIMITER ;;
CREATE PROCEDURE `lock_test`(OUT status ENUM('success','timeout'))
MODIFIES SQL DATA
BEGIN
START TRANSACTION;
SELECT * FROM `users` FOR UPDATE;
SET status := 'success';
COMMIT;
END;;
DELIMITER ;
2. Run code in mysql terminal 1:
START TRANSACTION;
SELECT * FROM `users` FOR UPDATE;
the contents of users will be displayed, but the transaction will remain open.
3. Run code in mysql terminal 2:
CALL `lock_test`(#out);
SELECT #out;
the transaction will run until it times out (default value of innodb_lock_wait_timeout is 50 seconds)
Is it possible to add a handler inside the lock_test() procedure, so that we can have #out hold 'timeout'?
After spending some time reading through the MySQL Handler Documentation I was able to get what I was looking for:
DROP PROCEDURE IF EXISTS `lock_test`;
DELIMITER ;;
CREATE PROCEDURE `lock_test`(OUT status_out VARCHAR(255))
MODIFIES SQL DATA
BEGIN
DECLARE procedure_attempts INT DEFAULT 5;
DECLARE query_timeout INT DEFAULT FALSE;
SET status_out := 'start';
procedure_loop:
REPEAT
BEGIN
DECLARE CONTINUE HANDLER FOR 1205
-- Error: 1205 SQLSTATE: HY000 (ER_LOCK_WAIT_TIMEOUT)
BEGIN
SET query_timeout := TRUE;
SET status_out := CONCAT(status_out,'-timeout');
END;
IF ( procedure_attempts < 1) THEN
LEAVE procedure_loop;
END IF;
START TRANSACTION;
SELECT * FROM `users` FOR UPDATE;
IF (query_timeout) THEN
SET query_timeout := FALSE;
ELSE
SET status_out := CONCAT(status_out,'-success');
SET procedure_attempts := 0;
END IF;
COMMIT;
SET procedure_attempts := procedure_attempts - 1;
END;
UNTIL FALSE END REPEAT;
-- loop
SET status_out := CONCAT(status_out,'-end');
END;;
DELIMITER ;
When run as follows:
SET ##innodb_lock_wait_timeout:=1;
CALL `lock_test`(#out);
SELECT #out;
The output will be start-timeout-timeout-timeout-timeout-timeout-end after about 10 seconds of running time (which would be much longer if run without setting the timeout to 1 second.
While probably not too practical (or advisable) in most projects, could potentially be useful when debugging timeout issues when running a query from inside another query - I hope it might help someone else in the future.

Mysql-Events: How get rid of Errors like No Data-zero rows fetched?

I just try to kill mysql jobs using event scheduler.
Unfortunately the event scheduler fills up my log file with error messages:
No Data - zero rows fetched
But I am catching the No data exception.
Why event still throws an error?
CREATE PROCEDURE `kill_run_aways`( IN runtime INT(7), IN username VARCHAR(32) )
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE connid INT UNSIGNED;
DECLARE cur1 CURSOR FOR SELECT ID FROM information_schema.PROCESSLIST
WHERE COMMAND ='Query'
AND TIME >= runtime AND USER = username;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur1;
REPEAT
FETCH cur1 INTO connid;
IF NOT done THEN
select * from information_schema.PROCESSLIST where connid=ID;
KILL connid;
END IF;
UNTIL done END REPEAT;
CLOSE cur1;
END;
Thanks Arman.
You should add SQL_CALC_FOUND_ROWS to your query in CURSOR. Next, after open command check whether your CURSOR returns more than one row, e.g.
DECLARE cur1 CURSOR FOR SELECT SQL_CALC_FOUND_ROWS '1' FROM DUAL;
OPEN cur1;
IF Select FOUND_ROWS() /* it concerns SQL_CALC_FOUND_ROWS */ > 0 THEN
-- do sth
ELSE
-- do sth else
END IF;
Your code is correct, but a bug/strange behaviour of MySQL causes the warning to appear even if it was handled. You can avoid that if you add a "dummy" statement to the end of your procedure that involves a table and is successful. This will clear the warning. (See http://dev.mysql.com/doc/refman/5.5/en/show-warnings.html)
In your case:
SELECT ID INTO connid FROM information_schema.PROCESSLIST LIMIT 1;
after the end of the loop. On MySQL 5.5.13 the warning disappears for Linux and Windows. I commented on MySQL Bug 60840 and I hope they will fix it some time in the future...
Mysql says that NOT FOUND "is relevant only within the context of cursors and is used to control what happens when a cursor reaches the end of a data set" (http://dev.mysql.com/doc/refman/5.5/en/declare-handler.html. So I believe you get this message when line select * from information_schema.PROCESSLIST where connid=ID; is executed.