MYSQL and random performance of store procedure
3
votes
1
answer
68
views
I run this SP at night, when there’s almost no activity. The SP performs an accumulative calculation of machine usage from a laundromat—an artisanal BI query. It writes the result to a table.
On most days, it takes about 5 minutes to finish. But randomly, it can take up to an hour—or it keeps running into business hours and I have to kill it.
The weirdest part is its inconsistency. For example, last week I had to kill it on Friday and Saturday, but on Sunday it finished quickly. Today it took around 1 hour and 40 minutes.
More details:
MySQL on AWS RDS, t3.micro, GP3 volume, no replica or multi-AZ setup.
I don’t see any CPU/memory issues in the Monitoring tab (as far as I can tell).
I recently upgraded MySQL from v5 to v8. On v5, the process always took more than an hour—and sometimes didn’t finish at all. After upgrading, I refactored the SP to use CTEs, which greatly improved performance (down to 5 minutes). I also created a few indexes to help with that.
I’ve tried rebuilding all indexes, tweaking the DB parameter group (based on some ChatGPT suggestions), and upgrading the RDS volume from GP2 to GP3, but none of that has helped. Everything still behaves the same.
More details:
- MySQL in AWS Rds, t3.micro, GP3, no replica or multizone.
- I don't see any CPU/Memory issues on the Monitoring tab (I think).
- I recently upgraded MySQL from v5 to v8. On v5 the process always took more than an hour and sometimes didn't finish and had to be killed. Therefore, I upgraded it to use CTEs and that improved the timing A LOT (down to 5 min). With that and the creation of a few indexes is how I managed that.
- I have tried to rebuild every index, tweak the db parameter group (some ChatGPT suggestions), upgraded the RDS volume from GP2 to GP3, but nothign helped, all seems to be the same.
Tables involed:
preventive_maintenance_building_entry
. This table is filled with a previous steps of a "orchestator" SP but those other steps are really fast.
SHOW CREATE TABLE preventive_maintenance_building_entry;
CREATE TABLE preventive_maintenance_building_entry
(
building_id
int NOT NULL,
maintenance_type
varchar(255) NOT NULL,
machine_id
int DEFAULT NULL,
maintenance_date
datetime DEFAULT NULL,
technician
varchar(255) DEFAULT NULL,
uses
int DEFAULT NULL,
created_at
datetime NOT NULL,
PRIMARY KEY (building_id
,created_at
,maintenance_type
),
KEY CREATED_AT
(created_at
),
KEY CREATED_AT_MAINTENANCE_TYPE
(created_at
,maintenance_type
),
KEY BUILDING_ID_MAINTENANCE_TYPE
(building_id
,maintenance_type
)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
machine_use
CREATE TABLE machine_use
(
id
int NOT NULL AUTO_INCREMENT,
headline
varchar(255) DEFAULT NULL,
timestamp
datetime DEFAULT NULL,
card_id
int DEFAULT NULL,
machine_id
int DEFAULT NULL,
uid
varchar(255) DEFAULT NULL,
energy_consumption
double NOT NULL,
result
varchar(255) DEFAULT NULL,
water_consumption
double NOT NULL,
bill_id
int DEFAULT NULL,
accredited
bit(1) DEFAULT b''1'',
reason
varchar(255) DEFAULT NULL,
transaction_id
int NOT NULL,
audit_id
int DEFAULT NULL,
channel
varchar(255) DEFAULT NULL,
building_id
int DEFAULT NULL,
PRIMARY KEY (id
),
UNIQUE KEY uk_machine_timestamp
(machine_id
,timestamp
),
KEY FK_c4b0xhdiy6ifa6dr0qhiybfyy
(card_id
),
KEY FK_87unujtk3bdckfoj3ts7qxj0o
(bill_id
),
KEY FK_pnc8o8pmdu5nhkuv6ex0c6j3u
(audit_id
),
KEY RESULT
(result
),
KEY TIMESTAMP
(timestamp
),
KEY BUILDING_ID_MACHINE_ID
(building_id
,machine_id
),
KEY BUILDING_ID_TIMESTAMP
(building_id
,timestamp
),
CONSTRAINT FK_87unujtk3bdckfoj3ts7qxj0o
FOREIGN KEY (bill_id
) REFERENCES bill
(id
) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT FK_c4b0xhdiy6ifa6dr0qhiybfyy
FOREIGN KEY (card_id
) REFERENCES part
(id
) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT FK_lkllr5f16o42yu0xykdjocjcj
FOREIGN KEY (building_id
) REFERENCES building
(id
) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT FK_mypy14i1gkixyeavmot7srv96
FOREIGN KEY (machine_id
) REFERENCES part
(id
) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT FK_pnc8o8pmdu5nhkuv6ex0c6j3u
FOREIGN KEY (audit_id
) REFERENCES audit
(id
) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE=InnoDB AUTO_INCREMENT=22049277 DEFAULT CHARSET=utf8mb3
part
CREATE TABLE part
(
from_class
varchar(50) NOT NULL,
id
int NOT NULL AUTO_INCREMENT,
description
varchar(255) DEFAULT NULL,
model
varchar(255) DEFAULT NULL,
name
varchar(255) DEFAULT NULL,
serial_number
varchar(255) DEFAULT NULL,
state
varchar(255) DEFAULT NULL,
uuid
varchar(255) DEFAULT NULL,
english_description
varchar(255) DEFAULT NULL,
machine_type
varchar(255) DEFAULT NULL,
unit_price
double DEFAULT NULL,
uy_price
double DEFAULT NULL,
anual_consumption
int DEFAULT NULL,
minimum_stock
int DEFAULT NULL,
request_point
int DEFAULT NULL,
unit_id
int DEFAULT NULL,
building_id
int DEFAULT NULL,
current_uses
int DEFAULT NULL,
expected_uses
int DEFAULT NULL,
balance
double DEFAULT NULL,
contract_type
varchar(255) DEFAULT NULL,
master
bit(1) DEFAULT NULL,
last_alive
datetime DEFAULT NULL,
port
varchar(255) DEFAULT NULL,
private_ip
varchar(255) DEFAULT NULL,
public_ip
varchar(255) DEFAULT NULL,
upgrade_to
varchar(255) DEFAULT NULL,
firmware_id
int DEFAULT NULL,
average_use_time
int DEFAULT NULL,
sub_state
varchar(255) DEFAULT NULL,
pending_uses
int DEFAULT NULL,
prepaidcardholder_id
int DEFAULT NULL,
end_time_of_use
datetime DEFAULT NULL,
start_time_of_use
datetime DEFAULT NULL,
machinerate_id
int DEFAULT NULL,
alias
varchar(255) DEFAULT NULL,
activation_status
varchar(255) DEFAULT NULL,
discount
double DEFAULT NULL,
sort_index
int DEFAULT NULL,
is_topic_enable
bit(1) DEFAULT NULL,
capacity
int DEFAULT NULL,
reference
varchar(255) DEFAULT NULL,
quantity
int DEFAULT NULL,
machinemodel_id
int DEFAULT NULL,
rpichild_id
int DEFAULT NULL,
firmware_version
varchar(255) DEFAULT NULL,
pre_blocked_uses
int DEFAULT NULL,
PRIMARY KEY (id
),
UNIQUE KEY PART_CARD_UUID
(uuid
),
KEY FK_68gfqjsfqvgxh7o10olfs4cin
(unit_id
),
KEY FK_k6kwvobmnq67he07u9shakwmv
(building_id
),
KEY FK_o6toyd4jag26vwtyayo7l2ng4
(firmware_id
),
KEY FK_fnbvj52u2i90s78wfqjgiip0x
(prepaidcardholder_id
),
KEY FK_shyirawpsc2lwvrj0hyo1o5hc
(machinerate_id
),
KEY MACHINE_KEEP_ALIVE
(last_alive
),
KEY FK_qd2kalbf8g1ep7be556fb9bm9
(machinemodel_id
),
KEY FK_nccjoenep9lhexhsr34ccrle2
(rpichild_id
),
KEY MACHINE_TYPE
(machine_type
),
KEY ID_MACHINE_TYPE
(id
,machine_type
),
KEY FROM_CLASS
(from_class
),
CONSTRAINT FK_68gfqjsfqvgxh7o10olfs4cin
FOREIGN KEY (unit_id
) REFERENCES unit
(id
) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT FK_fnbvj52u2i90s78wfqjgiip0x
FOREIGN KEY (prepaidcardholder_id
) REFERENCES user
(id
) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT FK_k6kwvobmnq67he07u9shakwmv
FOREIGN KEY (building_id
) REFERENCES building
(id
) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT FK_nccjoenep9lhexhsr34ccrle2
FOREIGN KEY (rpichild_id
) REFERENCES part
(id
) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT FK_o6toyd4jag26vwtyayo7l2ng4
FOREIGN KEY (firmware_id
) REFERENCES firmware
(id
) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT FK_qd2kalbf8g1ep7be556fb9bm9
FOREIGN KEY (machinemodel_id
) REFERENCES machine_model
(id
) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT FK_shyirawpsc2lwvrj0hyo1o5hc
FOREIGN KEY (machinerate_id
) REFERENCES rate
(id
) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE=InnoDB AUTO_INCREMENT=55621 DEFAULT CHARSET=utf8mb3
Query:
REPLACE INTO preventive_maintenance_building_entry(building_id,
maintenance_type,
machine_id,
maintenance_date,
technician,
uses,
created_at)
WITH PreventiveEntriesMP1200 AS (SELECT e1.building_id,
e1.maintenance_type,
e1.maintenance_date,
e1.technician,
e1.created_at
FROM preventive_maintenance_building_entry e1
WHERE e1.created_at = CURDATE()
AND e1.maintenance_type = 'MP1200'),
MachineUsage AS (SELECT mu1.building_id, mu1.machine_id, COUNT(*) AS use_count
FROM machine_use mu1
INNER JOIN PreventiveEntriesMP1200 pe
ON pe.building_id = mu1.building_id
INNER JOIN part p1
ON mu1.machine_id = p1.id
AND p1.machine_type = 'DRYER'
WHERE mu1.result IN ('0', '1', '5', '6', '7', '8', '30')
AND mu1.timestamp > pe.maintenance_date
GROUP BY mu1.building_id, mu1.machine_id),
MachineWithMostUses AS (SELECT building_id,
machine_id,
use_count,
ROW_NUMBER() OVER (
PARTITION BY building_id
ORDER BY use_count DESC
) AS ranking
FROM MachineUsage)
SELECT pmbe.building_id AS building_id,
pmbe.maintenance_type AS maintenance_type,
mwmu.machine_id AS machine_id,
pmbe.maintenance_date AS maintenance_date,
pmbe.technician AS technician,
mwmu.use_count AS uses,
pmbe.created_at AS created_at
FROM PreventiveEntriesMP1200 pmbe
INNER JOIN MachineWithMostUses mwmu
ON pmbe.building_id = mwmu.building_id
WHERE mwmu.ranking = 1;
Execution plan:
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
|----|-------------|-------------|------------|------------|--------------------------------------------------------------------------------|-------------------------------------------|---------|-------------------------------------|------|----------|-------------------------------------------------------------------------------------------|
| 1 | REPLACE | preventive_maintenance_building_entry | NULL | ALL | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| 1 | PRIMARY | e1 | NULL | index_merge| PRIMARY,CREATED_AT,CREATED_AT_MAINTENANCE_TYPE,BUILDING_ID_MAINTENANCE_TYPE | CREATED_AT,CREATED_AT_MAINTENANCE_TYPE | 5,262 | NULL | 3 | 99.43 | Using intersect(CREATED_AT,CREATED_AT_MAINTENANCE_TYPE); Using where; Using temporary |
| 1 | PRIMARY | | NULL | ref | | | 13 | lavomat.e1.building_id,const | 10 | 100.00 | NULL |
| 3 | DERIVED | | NULL | ALL | NULL | NULL | NULL | NULL | 429 | 100.00 | Using filesort |
| 4 | DERIVED | e1 | NULL | index_merge| PRIMARY,CREATED_AT,CREATED_AT_MAINTENANCE_TYPE,BUILDING_ID_MAINTENANCE_TYPE | CREATED_AT,CREATED_AT_MAINTENANCE_TYPE | 5,262 | NULL | 3 | 99.43 | Using intersect(CREATED_AT,CREATED_AT_MAINTENANCE_TYPE); Using where; Using temporary |
| 4 | DERIVED | mu1 | NULL | ref | uk_machine_timestamp,RESULT,TIMESTAMP,BUILDING_ID_MACHINE_ID,BUILDING_ID_TIMESTAMP | BUILDING_ID_MACHINE_ID | 5 | lavomat.e1.building_id | 9598 | 29.81 | Using index condition; Using where |
| 4 | DERIVED | p1 | NULL | eq_ref | PRIMARY,MACHINE_TYPE,ID_MACHINE_TYPE | PRIMARY | 4 | lavomat.mu1.machine_id | 1 | 5.00 | Using where |
This is a little benchmark table that I record when SPs start/finish.
| Timestamp | Status | Process |
|---------------------|--------|-------------------------------------------|
| 2025-04-09 05:01:31 | Start | FillPreventiveMP1200MaintenanceBuildingEntry |
| 2025-04-09 05:07:09 | Finish | FillPreventiveMP1200MaintenanceBuildingEntry |
| 2025-04-10 05:01:43 | Start | FillPreventiveMP1200MaintenanceBuildingEntry |
| 2025-04-10 05:07:24 | Finish | FillPreventiveMP1200MaintenanceBuildingEntry |
| 2025-04-11 07:58:07 | Start | FillPreventiveMP1200MaintenanceBuildingEntry |
| 2025-04-12 05:55:34 | Start | FillPreventiveMP1200MaintenanceBuildingEntry |
| 2025-04-13 05:01:47 | Start | FillPreventiveMP1200MaintenanceBuildingEntry |
| 2025-04-13 05:04:46 | Finish | FillPreventiveMP1200MaintenanceBuildingEntry |
| 2025-04-14 06:14:19 | Start | FillPreventiveMP1200MaintenanceBuildingEntry |
| 2025-04-14 06:50:36 | Finish | FillPreventiveMP1200MaintenanceBuildingEntry |
| 2025-04-15 06:14:29 | Start | FillPreventiveMP1200MaintenanceBuildingEntry |
| 2025-04-15 06:50:43 | Finish | FillPreventiveMP1200MaintenanceBuildingEntry |
| 2025-04-16 06:12:31 | Start | FillPreventiveMP1200MaintenanceBuildingEntry |
| 2025-04-16 06:48:06 | Finish | FillPreventiveMP1200MaintenanceBuildingEntry |
Days with no Finish
record means it was killed.
Asked by chronotrigger
(31 rep)
Apr 14, 2025, 02:33 PM
Last activity: Apr 20, 2025, 11:35 PM
Last activity: Apr 20, 2025, 11:35 PM