DELIMITER // -- This index covers MonitorId grouping, StartDateTime ranges, -- Archived status filtering, and includes DiskSpace for summation. SET @s = (SELECT IF( (SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS WHERE table_schema = DATABASE() AND table_name = 'Events' AND index_name = 'Events_Summaries_Performance_idx' ) > 0, "SELECT 'Events_Summaries_Performance_idx already exists'", "CREATE INDEX Events_Summaries_Performance_idx ON Events (MonitorId, StartDateTime, Archived, DiskSpace)" ))// PREPARE stmt FROM @s// EXECUTE stmt// DEALLOCATE PREPARE stmt// -- Clean up a previous typoed version of the index SET @s = (SELECT IF( (SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS WHERE table_schema = DATABASE() AND table_name = 'Events' AND index_name = 'Events_Summaries_Perfomance_idx' ) > 0, "DROP INDEX Events_Summaries_Perfomance_idx ON Events", "SELECT 'Events_Summaries_Perfomance_idx does not exist'" ))// PREPARE stmt FROM @s// EXECUTE stmt// DEALLOCATE PREPARE stmt// -- Hourly Events View CREATE OR REPLACE VIEW Events_Hour AS SELECT Id AS EventId, MonitorId, DiskSpace, StartDateTime FROM Events WHERE StartDateTime >= (NOW() - INTERVAL 1 HOUR)// -- Daily Events View CREATE OR REPLACE VIEW Events_Day AS SELECT Id AS EventId, MonitorId, DiskSpace, StartDateTime FROM Events WHERE StartDateTime >= (NOW() - INTERVAL 1 DAY)// -- Weekly Events View CREATE OR REPLACE VIEW Events_Week AS SELECT Id AS EventId, MonitorId, DiskSpace, StartDateTime FROM Events WHERE StartDateTime >= (NOW() - INTERVAL 7 DAY)// -- Monthly Events View CREATE OR REPLACE VIEW Events_Month AS SELECT Id AS EventId, MonitorId, DiskSpace, StartDateTime FROM Events WHERE StartDateTime >= (NOW() - INTERVAL 1 MONTH)// -- Archived Events View CREATE OR REPLACE VIEW Events_Archived AS SELECT Id AS EventId, MonitorId, DiskSpace FROM Events WHERE Archived = 1// -- Event Summaries Source View (used by the refresh procedure) CREATE OR REPLACE VIEW VIEW_Event_Summaries AS SELECT MonitorId, -- Hour Stats COUNT(CASE WHEN StartDateTime >= (NOW() - INTERVAL 1 HOUR) THEN 1 END) AS HourEvents, COALESCE(SUM(CASE WHEN StartDateTime >= (NOW() - INTERVAL 1 HOUR) THEN DiskSpace ELSE 0 END), 0) AS HourEventDiskSpace, -- Day Stats COUNT(CASE WHEN StartDateTime >= (NOW() - INTERVAL 1 DAY) THEN 1 END) AS DayEvents, COALESCE(SUM(CASE WHEN StartDateTime >= (NOW() - INTERVAL 1 DAY) THEN DiskSpace ELSE 0 END), 0) AS DayEventDiskSpace, -- Week Stats COUNT(CASE WHEN StartDateTime >= (NOW() - INTERVAL 7 DAY) THEN 1 END) AS WeekEvents, COALESCE(SUM(CASE WHEN StartDateTime >= (NOW() - INTERVAL 7 DAY) THEN DiskSpace ELSE 0 END), 0) AS WeekEventDiskSpace, -- Month Stats COUNT(CASE WHEN StartDateTime >= (NOW() - INTERVAL 1 MONTH) THEN 1 END) AS MonthEvents, COALESCE(SUM(CASE WHEN StartDateTime >= (NOW() - INTERVAL 1 MONTH) THEN DiskSpace ELSE 0 END), 0) AS MonthEventDiskSpace, -- Archive Stats COUNT(CASE WHEN Archived = 1 THEN 1 END) AS ArchivedEvents, COALESCE(SUM(CASE WHEN Archived = 1 THEN DiskSpace ELSE 0 END), 0) AS ArchivedEventDiskSpace, -- Totals COUNT(Id) AS TotalEvents, COALESCE(SUM(DiskSpace), 0) AS TotalEventDiskSpace FROM Events GROUP BY MonitorId// -- Event Summaries snapshot table (SWR pattern) CREATE TABLE IF NOT EXISTS `Event_Summaries` ( `MonitorId` int(10) unsigned NOT NULL, `HourEvents` int(10) DEFAULT 0, `HourEventDiskSpace` bigint DEFAULT 0, `DayEvents` int(10) DEFAULT 0, `DayEventDiskSpace` bigint DEFAULT 0, `WeekEvents` int(10) DEFAULT 0, `WeekEventDiskSpace` bigint DEFAULT 0, `MonthEvents` int(10) DEFAULT 0, `MonthEventDiskSpace` bigint DEFAULT 0, `ArchivedEvents` int(10) DEFAULT 0, `ArchivedEventDiskSpace` bigint DEFAULT 0, `TotalEvents` int(10) DEFAULT 0, `TotalEventDiskSpace` bigint DEFAULT 0, PRIMARY KEY (`MonitorId`) ) ENGINE=InnoDB// -- Metadata table for SWR staleness tracking CREATE TABLE IF NOT EXISTS `Event_Summaries_Metadata` ( `table_name` VARCHAR(64) NOT NULL, `last_updated` DATETIME NOT NULL DEFAULT '1970-01-01 00:00:00', PRIMARY KEY (`table_name`) ) ENGINE=InnoDB// INSERT IGNORE INTO `Event_Summaries_Metadata` (`table_name`, `last_updated`) VALUES ('Event_Summaries', '1970-01-01 00:00:00')// -- Stored procedure: atomic refresh of Event_Summaries with GET_LOCK to prevent thundering herd DROP PROCEDURE IF EXISTS `Refresh_Summaries_SWR`// CREATE PROCEDURE `Refresh_Summaries_SWR`() proc: BEGIN DECLARE v_lock_result INT DEFAULT 0; DECLARE v_last DATETIME; -- Use READ COMMITTED so the INSERT...SELECT below performs a consistent -- snapshot read on Events without taking shared next-key locks. Under the -- default REPEATABLE READ (and STATEMENT binlog format) the source-side -- locks deadlock with concurrent DELETE FROM Events. SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; -- Non-blocking lock: skip if another process is already refreshing SET v_lock_result = GET_LOCK('refresh_summaries_lock', 0); IF v_lock_result != 1 THEN -- Another process holds the lock; return immediately (stale read is fine) LEAVE proc; END IF; -- Double-check staleness inside lock SELECT `last_updated` INTO v_last FROM `Event_Summaries_Metadata` WHERE `table_name` = 'Event_Summaries'; IF v_last IS NOT NULL AND TIMESTAMPDIFF(SECOND, v_last, NOW()) < 60 THEN DO RELEASE_LOCK('refresh_summaries_lock'); LEAVE proc; END IF; -- Atomic rename pattern: build new table, swap, drop old DROP TABLE IF EXISTS `Event_Summaries_New`; CREATE TABLE `Event_Summaries_New` LIKE `Event_Summaries`; INSERT INTO `Event_Summaries_New` SELECT * FROM `VIEW_Event_Summaries`; DROP TABLE IF EXISTS `Event_Summaries_Old`; RENAME TABLE `Event_Summaries` TO `Event_Summaries_Old`, `Event_Summaries_New` TO `Event_Summaries`; DROP TABLE IF EXISTS `Event_Summaries_Old`; -- Update metadata timestamp UPDATE `Event_Summaries_Metadata` SET `last_updated` = NOW() WHERE `table_name` = 'Event_Summaries'; DO RELEASE_LOCK('refresh_summaries_lock'); END proc// -- MySQL EVENT for background refresh every 600 seconds (10 minutes) -- Note: Requires event_scheduler=ON in my.cnf or SET GLOBAL event_scheduler = ON; DROP EVENT IF EXISTS `Event_Summaries_Refresh_Event`// CREATE EVENT IF NOT EXISTS `Event_Summaries_Refresh_Event` ON SCHEDULE EVERY 600 SECOND DO CALL `Refresh_Summaries_SWR`()// DELIMITER ;