Why Adding LIMIT 1 Can Slow Down MySQL Queries 50× and How to Fix It
A MySQL query that should return a single row became 50 times slower after adding LIMIT 1 because the optimizer chose a suboptimal index, and the article explains the root cause and three practical ways to resolve the issue.
When writing SQL, many developers add LIMIT 1 to fetch a single row, assuming it speeds up the query. In a real‑world case, adding LIMIT 1 made the query 50 times slower.
1. Reproduce the scenario
The business requirement is to find the most recent "processing" order for a user. The orders table contains about 5 million rows and has two key indexes:
idx_user_status ( (user_id, status)) – used for filtering by user and status.
idx_create_time ( (create_time)) – used for ordering by time.
The original query that triggered the problem:
SELECT id, order_no, amount
FROM orders
WHERE user_id = 10086 AND status = 1
ORDER BY create_time DESC
LIMIT 1;Running this query generated a slow‑query alert, taking about 2.5 seconds. Removing LIMIT 1 reduced the execution time to roughly 50 ms.
2. Explain analysis
Using EXPLAIN revealed the optimizer's choices:
Without LIMIT: MySQL used idx_user_status, quickly filtered the few matching rows and performed an in‑memory sort – fast because the data set was small.
With LIMIT: MySQL switched to idx_create_time, scanning the table in descending create_time order and checking each row for the user and status. The matching row was over a year old, so MySQL scanned more than 2 million rows before finding it, effectively turning the query into a near full‑table scan.
The optimizer "guessed" that it would encounter a matching row early, a bet that failed due to highly skewed data distribution.
3. Solutions
Method 1: FORCE INDEX
SELECT ... FROM orders FORCE INDEX (idx_user_status) ...;This forces the optimizer to use the filtering index, but ties the query to a specific index name.
Method 2: Create a covering 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 row and return it already sorted, eliminating the extra sort step.
Method 3: Subquery trick
SELECT * FROM (
SELECT ... FROM orders
WHERE user_id = 10086 AND status = 1
ORDER BY create_time DESC
) AS tmp
LIMIT 1;The inner query uses the filtering index; the outer LIMIT 1 does not influence the inner index choice, effectively separating the limit from the index selection.
Conclusion
While LIMIT 1 is generally a good habit, it can backfire when the optimizer mis‑estimates row distribution. In such cases, examine the execution plan with EXPLAIN and consider forcing the appropriate index, adding a composite index, or rewriting the query with a subquery.
IT Services Circle
Delivering cutting-edge internet insights and practical learning resources. We're a passionate and principled IT media platform.
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.
