Looking for some advice please :
I have a MySQL 5.6 Event scheduler set up as below:
DELIMITER $$
CREATE DEFINER=`root`#`10.0.0.%` EVENT `update_reports` ON SCHEDULE EVERY 3 MINUTE STARTS '2015-10-16 13:01:20' ON COMPLETION PRESERVE ENABLE DO update_reports:BEGIN
DECLARE triggered datetime DEFAULT SYSDATE();
DECLARE started datetime DEFAULT NULL;
DECLARE status tinyint(1) DEFAULT 0;
# LOGIC
IF wait_for_processing('reports.processing') THEN
SET started = SYSDATE();
# SET SESSION VARIABLES
SELECT enable_logging(false);
SELECT enable_debug_timers(true);
SET #reporting_from = '2013-03-01 00:00:00';
IF (needs_update()) THEN
SELECT update_usage_data();
SET status = 1;
ELSE
SET status = 2;
END IF;
SELECT free_for_processing('reports.processing');
END IF;
INSERT INTO ref.event_logs
SELECT
'reports',
'update_reports',
triggered,
started,
SYSDATE(),
null,
status;
END update_reports
However, in the MySql Error log I am receiving this error:
2015-10-16 13:37:20 29327 [ERROR] Event Scheduler: [root#10.0.0.%][reports.update_reports] Table 'reports.reporting_statsevent_logsuser_seen' doesn't exist
2015-10-16 13:37:20 29327 [Note] Event Scheduler: [root#10.0.0.%].[reports.update_reports] event execution failed.
Permissions on the database and tables show root#10.0.0.% to have full permissions.
Could anyone please share any troubleshooting steps I can take to understand why the event scheduler cannot access the tables, yet the queries work fine when carried out in MySql Workbench.
Thank you.
Related
I am facing an issue want to updating the message table column DateTime using the MySQL event scheduler On DateTime '2022-02-23 23:58:00' where status is open and mes_type is SSG. Please help me to correct my code I will be thankful to you.
DELIMITER $$
CREATE EVENT my_event
ON SCHEDULE AT '2022-02-24 23:58:00'
DO
UPDATE MESSAGE
SET datetime = '2022-03-01 23:59:00'
WHERE datetime = '2022-02-23 23:59:00'
AND STATUS = 'OPEN' and MES_TYPE = 'SSG'
END */$$
DELIMITER ;
You have only 1 statement so you don't need to set delimiters and the end statement is unnecessary but you do need to terminate the update
CREATE EVENT my_event
ON SCHEDULE AT '2022-02-24 23:58:00'
DO
UPDATE MESSAGE
SET datetime = '2022-03-01 23:59:00'
WHERE datetime = '2022-02-23 23:59:00'
AND STATUS = 'OPEN' and MES_TYPE = 'SSG';
I have a Spring Boot application with mysql as db. To achieve some requirement, I have implemented a stored procedure in MySql and triggering it through my spring boot code.
However, what I am observing is, After my spring boot code is triggered, mysql is idle for around 90 seconds. After that procedure execution starts. This is slowing the system down. Any suggestions if this is expected or I am doing something wrong.
Below is my spring code to invoke procedure
#PersistenceContext
private EntityManager entityManager;
#Transactional
public void backFillClosingStock(String dbName, String id_list) throws Exception {
try {
ThreadLocalStorage.setTenantName(dbName);
log.info("Starting backfilling closing stock");
StoredProcedureQuery storedProcedure = entityManager.createStoredProcedureQuery("update_closing_stock");
storedProcedure.registerStoredProcedureParameter("id_list", String.class, ParameterMode.IN);
storedProcedure.setParameter("id_list", id_list );
storedProcedure.execute();
ThreadLocalStorage.setTenantName(null);
log.info("Completed backfilling closing stock");
} catch (Exception e) {
throw new Exception("something went wrong!");
}
And below is my stored procedure.
DELIMITER //
DROP PROCEDURE IF EXISTS update_closing_stock//
CREATE PROCEDURE update_closing_stock(id_list TEXT)
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE entryid1 decimal;
DECLARE oldClosingStock decimal;
DECLARE newClosingStock decimal;
DECLARE isValueChanged INT DEFAULT 0;
DECLARE cur CURSOR FOR SELECT entryid FROM inward_outward_entries WHERE FIND_IN_SET(productId,id_list)>0 AND is_deleted=0;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
SET autocommit=0;
TRUNCATE temp;
INSERT INTO temp VALUES (CONCAT('Procedure Started ',SYSDATE()));
OPEN cur;
ins_loop: LOOP
FETCH cur INTO entryid1;
IF done THEN
LEAVE ins_loop;
END IF;
SELECT
bs1.closingStock as oldClosingStock,
CASE WHEN bs1.type='Inward' THEN(
(SELECT CASE WHEN SUM(bs2.quantity) IS NULL THEN 0 ELSE SUM(bs2.quantity) END FROM backfill_closing_stock bs2
WHERE bs2.id>=bs1.id AND bs2.type='Inward' AND bs1.Productid=bs2.productid AND bs2.warehouseid=bs1.warehouseid)
-
(SELECT CASE WHEN SUM(bs2.quantity)IS NULL THEN 0 ELSE SUM(bs2.quantity) END FROM backfill_closing_stock bs2
WHERE bs2.id>bs1.id AND bs2.type!='Inward' AND bs1.Productid=bs2.productid AND bs2.warehouseid=bs1.warehouseid)
)
ELSE (
(SELECT CASE WHEN SUM(bs2.quantity) IS NULL THEN 0 ELSE SUM(bs2.quantity) END FROM backfill_closing_stock bs2
WHERE bs2.id>bs1.id AND bs2.type='Inward' AND bs1.Productid=bs2.productid AND bs2.warehouseid=bs1.warehouseid)
-
(SELECT CASE WHEN SUM(bs2.quantity) IS NULL THEN 0 ELSE SUM(bs2.quantity) END FROM backfill_closing_stock bs2
WHERE bs2.id>=bs1.id AND bs2.type!='Inward' AND bs1.Productid=bs2.productid AND bs2.warehouseid=bs1.warehouseid)
)
END AS closingStock
INTO oldClosingStock,newClosingStock
FROM backfill_closing_stock bs1 WHERE bs1.entryid=entryid1;
IF newClosingStock>=0 AND newClosingStock<>oldClosingStock THEN
UPDATE inward_outward_entries SET closingStock = newClosingStock WHERE entryid=entryid1;
END IF;
END LOOP;
CLOSE cur;
TRUNCATE all_inventory_table;
INSERT INTO all_inventory_table SELECT * FROM all_inventory;
SET autocommit=1;
END;
I have two commands in line #13 and #14 resp. for truncating a table and inserting record to it for debugging purpose. I can see table getting truncated instantly but record with text "Procedure Started " is getting inserted to temp table only after 90 sec of execution. Not Sure where it is going wrong
Below is snippet from my logs
2022-01-27 09:49:33,165 INFO [Async-1] com.ec.application.service.AsyncServiceInventory: Before Procedure Start -2022-01-27T10:12:58.616
This shows that procedure was triggered from spring at 10:12:58
But when I check temp table, I do not see any record getting inserted for next 90 seconds. After that, say at 10:14:30, I see a record getting inserted with past time "Procedure Started 2022-01-27 10:12:58'"
I am not sure whats happening for this 90 seconds. any suggestions?
TRUNCATE (and other DDL statements) interrupts commits -- at least before MySQL 8.0
autocommit=0 is error-prone -- if you forget to COMMIT later, bad things can happen.
So, don't bother with autocommit and get the TRUNCATEs over with. Then do
START TRANSACTION;
do all the rest of the work
COMMIT;
But for real performance gains, find a way to rewrite it so you don't need a cursor. Cursors are slow.
I'd like (if it possible) check a time and if time = special time, make update of the table.
My idea:
select current_time()
if current_time = 15:19
{
update tasks set finished = replace (finished, '1', '0')
}
Do you have any ideas???
Use an event for that
delimiter //
CREATE EVENT IF NOT EXISTS your_event
ON SCHEDULE EVERY 1 DAY
STARTS '2014-07-04 15:19:00'
ON COMPLETION PRESERVE ENABLE
DO
update tasks
set finished = replace (finished, '1', '0');
//
It will be executed automatically every day on the defined time.
Can someone please tell me what's wrong with this sp. The logic seems to be ok, but when i check back in my table it doesn't work at all.
DELIMITER //
DROP PROCEDURE IF EXISTS add_zero_yearly_sales_proc //
CREATE PROCEDURE add_zero_yearly_sales_proc()
READS SQL DATA
BEGIN
DECLARE num_of_sales INT DEFAULT 0;
DECLARE last_ins_date DATETIME;
DECLARE done INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
SET last_ins_date = DATE_SUB(NOW(), INTERVAL 2 YEAR);
ins_loop: WHILE last_ins_date < NOW() DO
SELECT COUNT(sales_amount_sold) INTO num_of_sales
FROM yearly_sales
WHERE sales_date_sold BETWEEN DATE_FORMAT(last_ins_date,'%Y-%m-01 00:00:01') AND DATE_FORMAT(LAST_DAY(last_ins_date),'%Y-%m-%d 23:59:59');
IF num_of_sales = 0 THEN
INSERT INTO yearly_sales(sales_date_sold, sales_amount_sold,sales_quantity)
VALUES (CONCAT(DATE_FORMAT(last_ins_date,'%Y-%m-01 00:00:01')),0, 0);
END IF ;
SET num_of_sales = 0;
SET last_ins_date = DATE_ADD(last_ins_date, INTERVAL 1 MONTH);
END WHILE ins_loop;
SET done = 0;
END ;//
DELIMITER ;
I've created an event that fires every hour to call this procedure. The procedure is supposed to check if there are months in the yearly_sales table without any sales values in them, and if so add 0 values for the amount & quantity, and the beginning of the month for the date. I've checked back but it doesn't seem to work.
Also here's the event i created to call it hourly
DELIMITER //
CREATE
EVENT `hourly_sales_evt`
ON SCHEDULE EVERY 1 HOUR STARTS DATE_FORMAT(NOW(),'%Y-%m-%d %H:55:00')
ON COMPLETION PRESERVE
DO BEGIN
CALL add_zero_yearly_sales_proc();
END //
DELIMITER ;
May be global event scheduler is in stopped/disabled state.
To turn on event scheduler, run any of the following:
SET GLOBAL event_scheduler = ON;
SET ##global.event_scheduler = ON;
SET GLOBAL event_scheduler = 1;
SET ##global.event_scheduler = 1;
When the Event Scheduler is ON, the event scheduler thread is listed in the output of SHOW PROCESSLIST as a daemon process, and its state is represented as shown here:
mysql> SHOW PROCESSLIST\G
*************************** 1. row ***************************
Id: 1
User: root
Host: localhost
db: NULL
Command: Query
Time: 0
State: NULL
Info: show processlist
*************************** 2. row ***************************
Id: 2
User: event_scheduler
Host: localhost
db: NULL
Command: Daemon
Time: 3
State: Waiting for next activation
Info: NULL
2 rows in set (0.00 sec)
Once the Event Scheduler is set ON, you would see it working.
Refer to : MySQL Event Scheduler Configuration
The procedure looks OK, the logic should work. But, I want to ask you - why do you check sales_date_sold from first second -DATE_FORMAT(last_ins_date,'%Y-%m-01 00:00:01'), shouldn't it be DATE_FORMAT(last_ins_date,'%Y-%m-01 00:00:00')?
Another point: you execute SELECT statement many times in the loop, it is not effective. Try to create additional (maybe temporary table) with month numbers and join two tables to find out months without any sales. In this case you will achieve result in one step.
I'm taking a guess here without doing much digging, but I think this is your issue:
READS SQL DATA
...
INSERT INTO yearly_sales(sales_date_sold, sales_amount_sold,sales_quantity)
VALUES (CONCAT(DATE_FORMAT(last_ins_date,'%Y-%m-01 00:00:01')),0, 0);
As I know, I can define exception handler in MySQL stored procedure, but seems I can't catch the exception message in the handler and write a log in a table for debugging purpose. I just want to know is there method to log exception code and message in MySQL store procedure?
You can catch the message, the error code, the sql state, ..., with the GET DIAGNOSTICS statement, in 5.6.4
See
http://dev.mysql.com/doc/refman/5.6/en/get-diagnostics.html
I don't remember what tutorial I copied this from. However, it has helped immensely in the versions of MySQL prior to 5.6. Thanks to whomever I learned this from!
Step 1 : Create a debug_log table. This will hold everything your write to it.
CREATE TABLE `debug_log` (
`debug_log_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`msg` varchar(512) NOT NULL,
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`debug_log_id`)
) ENGINE=MyISAM
Step 2 : Create a stored procedure for adding info to the debug_log table.
DELIMITER $$
USE `your_db_name_here`$$
DROP PROCEDURE IF EXISTS `log_debug`$$
CREATE DEFINER=`ss7admin`#`%` PROCEDURE `log_debug`(IN lastMsg VARCHAR(512))
BEGIN
INSERT INTO debug_log (msg) VALUES (lastMsg);
END$$
DELIMITER ;
Step 3 : Add a handler in your real stored procedure.
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
CALL log_debug(
CONCAT
(
now(),
' : Something went horribly wrong!',
'.'
)
);
CALL log_debug('Exiting now');
SET outReturnCode = 1;
END;
You cannot catch the message, but you can catch the error code.
Here is an example of how to deal with "Duplicate entry" (PK, UK constraint):
CREATE PROCEDURE sp_do_insert(
IN in_param1 int,
IN in_param2 int,
OUT out_status tinyint
)
BEGIN
DECLARE CONTINUE HANDLER FOR 1062 SET out_status = 1;
SET out_status = 0;
INSERT INTO tbl(field1, fiel2)
VALUES (in_param1, in_param2);
END;
If tbl has a UK constraint on field1 and you try to insert an existing value once again you will not get an error. Nothing will be inserted and status will be equal to 1.
You can also add other handlers for other error codes. And you will always know what is the error from out_status value and you will know "error message" from error_code (in handler).
You can try to play with show warnings (it shows errors/warnings for the last query) in case if out_status <> 0.
Hope it helps.