Managing long-running transactions is crucial for maintaining the performance and stability of your MySQL databases. This guide provides a comprehensive solution to automatically identify and terminate the longest-running transactions that exceed 300 seconds, especially when the number of concurrent threads surpasses 300. Additionally, it logs detailed information about the killed sessions, including the current SQL statement and the history of the last 10 SQL statements executed during the session.
The solution involves creating a stored procedure that performs the following tasks:
Before implementing the stored procedure, ensure the following:
First, create a table to store information about the killed sessions. This table will capture essential details, including the current SQL statement and the history of the last 10 SQL statements executed by the session.
CREATE TABLE killed_sessions (
id INT AUTO_INCREMENT PRIMARY KEY,
session_id INT,
user VARCHAR(255),
host VARCHAR(255),
current_sql TEXT,
history_sql TEXT,
kill_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
The Performance Schema provides detailed insights into the execution of SQL statements, which is essential for retrieving the history of SQL commands executed by a session.
Modify your MySQL configuration file (my.cnf or my.ini) to enable the Performance Schema:
[mysqld]
performance_schema=ON
After making changes to the configuration file, restart the MySQL server to apply the changes.
The core component of this solution is the stored procedure that identifies and terminates long-running transactions while logging relevant session information.
kill_long_transactions
DELIMITER $$
CREATE PROCEDURE kill_long_transactions()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE proc_id INT;
DECLARE current_sql TEXT;
DECLARE history_sqls TEXT;
DECLARE thread_count INT;
-- Cursor to select process IDs with queries exceeding 300 seconds
DECLARE cur1 CURSOR FOR
SELECT ID
FROM information_schema.processlist
WHERE Command = 'Query'
AND Time > 300;
-- Handler for when no more rows are found
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
-- Get the current number of active threads
SET thread_count = (SELECT COUNT(*) FROM information_schema.processlist WHERE Command = 'Query');
-- Proceed only if concurrent threads exceed 300
IF thread_count > 300 THEN
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO proc_id;
IF done THEN
LEAVE read_loop;
END IF;
-- Retrieve the current SQL statement of the process
SET @current_sql = (
SELECT INFO
FROM information_schema.processlist
WHERE ID = proc_id
);
-- Retrieve the last 10 SQL statements from the Performance Schema
SET @history_sqls = (
SELECT GROUP_CONCAT(EVENT_SQL_TEXT SEPARATOR '; ')
FROM performance_schema.events_statements_history
WHERE THREAD_ID = (
SELECT THREAD_ID
FROM performance_schema.threads
WHERE PROCESSLIST_ID = proc_id
)
ORDER BY EVENT_ID DESC
LIMIT 10
);
-- Insert the session information into the killed_sessions table
INSERT INTO killed_sessions (session_id, user, host, current_sql, history_sql)
VALUES (
proc_id,
(SELECT USER FROM information_schema.processlist WHERE ID = proc_id),
(SELECT HOST FROM information_schema.processlist WHERE ID = proc_id),
@current_sql,
@history_sqls
);
-- Terminate the offending process
KILL proc_id;
-- Clear variables for the next iteration
SET @current_sql = NULL;
SET @history_sqls = NULL;
END LOOP;
CLOSE cur1;
END IF;
END$$
DELIMITER ;
done: Flag to indicate the end of the cursor.proc_id: Variable to store the process ID of each query.current_sql and history_sqls: Variables to store SQL statements.thread_count: Variable to store the number of current threads.cur1: Selects the IDs of all processes executing queries that have been running longer than 300 seconds.done to TRUE.killed_sessions table.KILL command.To ensure continuous monitoring, schedule the stored procedure to run at regular intervals using the MySQL Event Scheduler.
Ensure the Event Scheduler is enabled. You can check its status and enable it if necessary:
-- Check if the Event Scheduler is enabled
SHOW VARIABLES LIKE 'event_scheduler';
-- Enable the Event Scheduler if it's OFF
SET GLOBAL event_scheduler = ON;
To make the Event Scheduler persistent across server restarts, add the following line to your MySQL configuration file:
event_scheduler=ON
Create an event that calls the kill_long_transactions procedure every minute:
CREATE EVENT kill_long_transactions_event
ON SCHEDULE EVERY 1 MINUTE
DO CALL kill_long_transactions();
After setting up the stored procedure and scheduling the event, it's essential to verify that everything functions as expected.
Manually execute the stored procedure to ensure it operates correctly:
CALL kill_long_transactions();
Check the killed_sessions table to verify that session information is being logged accurately:
SELECT * FROM killed_sessions;
Ensure that the event is running as scheduled:
SHOW EVENTS LIKE 'kill_long_transactions_event';
This command will display the status of the event, confirming whether it's enabled and its next scheduled execution time.
The killed_sessions table is pivotal for auditing and troubleshooting. It records detailed information about each terminated session, enabling database administrators to analyze patterns, identify problematic queries, and optimize database performance.
The Performance Schema provides a wealth of information about SQL statement execution, including historical data. Leveraging this feature allows the stored procedure to retrieve a history of SQL statements, offering deeper insights into the behavior of terminated sessions.
Automating the execution of the stored procedure ensures that the monitoring mechanism operates consistently without manual intervention. Scheduling the procedure to run at defined intervals allows for timely detection and termination of problematic transactions.
Integrate a notification system (e.g., email alerts, Slack notifications) to inform administrators whenever a transaction is killed. This proactive approach enables quicker responses to potential issues.
Implement dynamic thresholds that adjust based on the time of day or current system load. This flexibility ensures that the monitoring mechanism adapts to varying workloads, reducing the likelihood of unnecessary terminations.
Enhance the logging table with additional fields such as transaction start time, client IP addresses, or application identifiers. This enriched data set facilitates more comprehensive analysis and reporting.
Effectively managing long-running transactions and high concurrency levels is essential for maintaining the health and performance of your MySQL databases. By implementing the stored procedure outlined in this guide, you can automate the identification and termination of problematic transactions while keeping detailed records for analysis and auditing purposes.
Remember to customize the thresholds and configurations to align with your specific operational requirements. Regularly review and update the monitoring strategy to adapt to evolving workloads and application behaviors.
For more detailed information, refer to the official MySQL documentation:
To manually execute the stored procedure and observe its behavior, follow these steps:
CALL kill_long_transactions();
SELECT * FROM killed_sessions ORDER BY kill_time DESC;
SHOW EVENTS LIKE 'kill_long_transactions_event';
These steps allow you to verify that the stored procedure is functioning correctly and that sessions are being appropriately terminated and logged.
Implementing automated management of long-running transactions enhances the resilience and efficiency of your database systems. By proactively monitoring and controlling resource-intensive operations, you ensure optimal performance and prevent potential bottlenecks.
Always tailor the solution to fit the unique demands of your environment, and continuously assess its impact to maintain a balance between performance and operational integrity.