Why Adding LIMIT 1 Can Make MySQL Queries 50× Slower—and How to Fix It
Adding a LIMIT 1 clause to a MySQL query that fetches the latest order for a user can unexpectedly trigger a full‑table scan, slowing execution by up to 50 times; this article explains the optimizer’s mis‑choice, shows EXPLAIN analysis, and offers three practical remedies.
When writing SQL, many developers habitually add LIMIT 1 to queries that only need a single row, assuming it will reduce I/O and CPU. However, a recent production incident showed that adding LIMIT 1 made a query 50 times slower.
Reproducing the Issue
The business requirement was to retrieve the most recent "processing" order for a specific user. The orders table contains about 5 million rows and has two key indexes:
idx_user_status ( (user_id, status)) – filters by user and status.
idx_create_time ( (create_time)) – supports ordering by time.
The original SQL was:
SELECT id, order_no, amount
FROM orders
WHERE user_id = 10086 AND status = 1
ORDER BY create_time DESC
LIMIT 1;Deployed to production, this query triggered a slow‑query alert and took 2.5 seconds . Removing the LIMIT 1 and running the same query without it reduced the execution time to about 50 ms .
Analyzing with EXPLAIN
Running EXPLAIN on both statements revealed the optimizer’s choices:
Without LIMIT: MySQL used idx_user_status, quickly filtering the few dozen rows that match the user and status, then sorting them in memory.
With LIMIT 1: MySQL abandoned the filtering index and chose idx_create_time, scanning the table in descending order of create_time and checking each row for the user and status condition.
The optimizer assumed it would find a matching row early in the time‑ordered scan, but because the target user’s latest qualifying order was over a year old, it had to scan more than 2 million rows before finding it.
Why the Optimizer Made the Wrong Choice
The optimizer evaluates two abstract plans:
Plan A – Filter Index First: Use idx_user_status to locate all matching rows, then sort them. This is efficient when many rows match the filter.
Plan B – Time Index + LIMIT: Use idx_create_time to read rows in the required order and stop after the first match. This avoids a separate sort but relies on the assumption that a matching row appears early.
In this case, the optimizer “bet” that Plan B would find a match quickly, but the data distribution (a sparse recent match) caused the bet to fail, resulting in a full‑table‑scan‑level slowdown.
How to Fix the Problem
Three practical solutions are presented:
1. Force the Desired Index
Use FORCE INDEX (idx_user_status) to tell MySQL to use the filtering index regardless of the LIMIT:
SELECT ... FROM orders FORCE INDEX (idx_user_status) ...;This immediately restores the fast execution path, though it ties the query to a specific index name.
2. Create a Composite Index
Build an index that satisfies both the filter and the ordering: (user_id, status, create_time) With this index, MySQL can locate the relevant rows and retrieve them already sorted, eliminating the need for a separate sort and avoiding the optimizer’s mis‑choice.
3. Use a Subquery to Isolate LIMIT
If changing the schema is not possible, rewrite the query so that the inner subquery uses the filtering index, and the outer query applies LIMIT 1:
SELECT * FROM (
SELECT ... FROM orders
WHERE user_id = 10086 AND status = 1
ORDER BY create_time DESC
) AS tmp
LIMIT 1;This prevents the LIMIT clause from influencing the inner index selection.
Takeaway
While LIMIT 1 is generally a good habit, it can backfire when the optimizer’s cost model mis‑estimates data distribution. Whenever a query with LIMIT becomes unexpectedly slow, run EXPLAIN to inspect the chosen plan and consider forcing an index, adding a composite index, or restructuring the query.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Su San Talks Tech
Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
