Databases 7 min read

MySQL CPU Saturation Case Study: Analyzing and Optimizing a Slow ORDER BY Query

This article examines a MySQL instance that hit 100% CPU at 9 am on 2019‑01‑11, identifies the offending ORDER BY query through slow‑log and EXPLAIN analysis, and demonstrates how adding a composite index and correcting implicit type conversions reduced execution time from over 10 seconds to milliseconds.

Aikesheng Open Source Community
Aikesheng Open Source Community
Aikesheng Open Source Community
MySQL CPU Saturation Case Study: Analyzing and Optimizing a Slow ORDER BY Query

Background

On 2019‑01‑11 at 9:00 AM a MySQL database on a server with 256 GB RAM and 48 CPU cores reached 100% CPU usage.

Analysis Process

Monitoring (PMM) showed the CPU spike coincided with a large number of slow queries. The most frequent entry in the slow‑log was extracted with: mysqldumpslow -s c slow.log > /tmp/slow_report.txt The top slow query scanned 1,161,559 rows (Rows_examined) indicating a full‑table (actually full‑index) scan.

Further investigation revealed the query:

SELECT T.TASK_ID, T.xx, ... FROM T_xxx_TASK T WHERE N=N AND T.STATUS IN (N,N,N) AND IFNULL(T.MAX_OPEN_TIMES,N) > IFNULL(T.OPEN_TIMES,N) AND (T.CLOSE_DATE IS NULL OR T.CLOSE_DATE >= SUBDATE(NOW(),INTERVAL 'S' MINUTE)) AND T.REL_DEVTYPE = N AND T.REL_DEVID = N AND T.TASK_DATE >= 'S' AND T.TASK_DATE <= 'S' ORDER BY TASK_ID DESC LIMIT N,N

The execution plan showed type: index (full‑index scan) and Rows: 644, which is only an estimate; the actual rows examined were over one million.

Key Findings

The index used (INDX_BIOM_ELOCK_TASK3) avoided a file sort but still required scanning many rows because the REL_DEVID column has high cardinality while TASK_DATE has low selectivity.

Using force index on the low‑selectivity index made the query faster, confirming that the optimizer’s cost‑based choice did not match real performance.

The Extra: Using where indicated a need for a covering index to avoid row look‑ups.

Optimization Recommendations

Add a composite index that matches the query predicates and the ORDER BY clause:

ALTER TABLE T_BIOMA_ELOCK_TASK ADD INDEX idx_REL_DEVID_TASK_ID (REL_DEVID, TASK_ID);

Also drop the low‑selectivity TASK_DATE index.

Note the implicit conversion issue: REL_DEVID is a VARCHAR, so the value must be quoted in the SQL (e.g., AND T.REL_DEVID = '000000025xxx').

Result

After adding the new index, the query execution time dropped from >10 seconds to 0.00 sec (milliseconds), confirming the effectiveness of the index redesign.

Conclusion

This typical ORDER BY query optimization demonstrates that an index appearing in the execution plan does not guarantee fast execution; the index must be well‑aligned with the query’s filter conditions and ordering requirements.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

performance tuningmysqlIndex Optimizationslow-query
Aikesheng Open Source Community
Written by

Aikesheng Open Source Community

The Aikesheng Open Source Community provides stable, enterprise‑grade MySQL open‑source tools and services, releases a premium open‑source component each year (1024), and continuously operates and maintains them.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.