Databases 7 min read

How I Reduced a 30,000‑second MySQL Query to 0.001s with Indexes & Joins

This article walks through a real‑world MySQL performance case where a nested sub‑query on millions of rows took over eight hours, explains why the plan used full table scans, and shows step‑by‑step index creation and query rewrites that cut the execution time to a millisecond.

21CTO
21CTO
21CTO
How I Reduced a 30,000‑second MySQL Query to 0.001s with Indexes & Joins

Scenario

The database is MySQL 5.6 with three tables: Course (100 rows), Student (70,000 rows), and SC (700,000 rows) that stores student scores.

CREATE TABLE Course(
  c_id INT PRIMARY KEY,
  name VARCHAR(10)
);

CREATE TABLE Student(
  id INT PRIMARY KEY,
  name VARCHAR(10)
);

CREATE TABLE SC(
  sc_id INT PRIMARY KEY,
  s_id INT,
  c_id INT,
  score INT
);

Original Query and Problem

Goal: find students who scored 100 in the Chinese subject (c_id = 0).

SELECT s.*
FROM Student s
WHERE s.s_id IN (
  SELECT s_id
  FROM SC sc
  WHERE sc.c_id = 0 AND sc.score = 100
);

Execution time: 30248.271 s (over 8 hours). The EXPLAIN plan shows type=ALL for all tables – no indexes are used.

First Optimization – Adding Indexes

CREATE INDEX sc_c_id_index ON SC(c_id);
CREATE INDEX sc_score_index ON SC(score);

Running the same query after adding the two indexes drops the time to 1.054 s , a >30,000× improvement, but still far from ideal.

Analyzing the Plan

The plan reveals that MySQL still scans many rows before applying the filter, so further tuning is needed.

Rewrite as EXISTS Sub‑query

SELECT `YSB`.`s`.`s_id` AS `s_id`, `YSB`.`s`.`name` AS `name`
FROM `YSB`.`Student` `s`
WHERE EXISTS (
  SELECT 1
  FROM `YSB`.`SC` `sc`
  WHERE `sc`.`c_id` = 0
    AND `sc`.`score` = 100
    AND `sc`.`s_id` = `s`.`s_id`
);

This version lets MySQL use the indexes efficiently and reduces the runtime dramatically.

Join‑based Rewrite

SELECT s.*
FROM Student s
INNER JOIN SC sc ON sc.s_id = s.s_id
WHERE sc.c_id = 0 AND sc.score = 100;

After temporarily dropping the previous indexes and creating an index on SC(s_id), the join query runs in 0.057 s . Adding the c_id and score indexes brings it down further.

Best Performing Form – Filter First, Then Join

SELECT s.*
FROM (
  SELECT *
  FROM SC sc
  WHERE sc.c_id = 0 AND sc.score = 100
) t
INNER JOIN Student s ON t.s_id = s.s_id;

With the three indexes ( sc_c_id_index, sc_score_index, sc_s_id_index) this query finishes in 0.001 s , a 50,000× speed‑up over the original.

Key Takeaways

Nested sub‑queries on large tables can be extremely slow if indexes are missing.

Converting the sub‑query to an EXISTS clause or a join often lets MySQL use indexes.

Creating appropriate indexes on the columns used in WHERE and join conditions is essential.

Analyzing the EXPLAIN plan helps identify why a query is not using indexes.

Further optimizations and more examples will be added later.

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.

mysqlindexesJOINSQL OptimizationSubquery
21CTO
Written by

21CTO

21CTO (21CTO.com) offers developers community, training, and services, making it your go‑to learning and service platform.

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.