SQL Indexes — Speeding Up Data Retrieval

Indexes

A school database has many students and often searches by city. Repeatedly scanning every record may become expensive.

An index is an additional data structure that can help a database locate or order matching records. The optimizer decides whether using it is worthwhile for a query.

  1. Explain and apply

    Create an index, describe the lookup it can support and explain why speed still needs measurement.

  2. Work it out

    Create a city index and read the Pune students. What should change about the logical answer?

  3. Avoid mistakes

    Indexes use storage and add work to writes.

Indexes: the request and its result

  1. School need

    A school database has many students and often searches by city. Repeatedly scanning every record may become expensive.

  2. Database operation

    An index is an additional data structure that can help a database locate or order matching records. The optimizer decides whether using it is worthwhile for a query.

  3. Check the outcome

    The index offers a possible access path. It must not change which city values match or which names are logically returned.

A conceptual model. The query examples below show the actual syntax, input data and results.

Understand what the database does

CREATE INDEX describes indexed expressions or columns. The database maintains that structure as data changes, and may use it to find a smaller candidate set. The query’s logical answer remains the same whether the optimizer uses an index or scans the table.

Related concepts: Read Execution Plans and Choose Effective Indexes.

What is an Index in SQL?

A SQL INDEX is a performance optimization structure. It allows the database to find and retrieve data faster — similar to how a book index helps locate chapters quickly.

When Should You Use Indexes?

  • On columns frequently used in WHERE clauses
  • On columns used in JOIN or ORDER BY
  • For large datasets where performance matters

Sample Table – students

SQL · portable concepts; preserved examples identify their engine

CREATE TABLE students (
  roll_no INT PRIMARY KEY,
  name VARCHAR(50),
  class VARCHAR(10),
  city VARCHAR(30)
);

INSERT INTO students VALUES
(1, 'Aarav Sharma', '10A', 'Delhi'),
(2, 'Diya Iyer', '9B', 'Chennai'),
(3, 'Sneha Patil', '10A', 'Pune'),
(4, 'Mehul Agarwal', '9B', 'Delhi'),
(5, 'Saira Bano', '8C', 'Hyderabad');

1. Create an Index on City

Create this fresh input before the example below. The fixture belongs to this section, so its result does not depend on visiting another section first.

CREATE TABLE students (
  roll_no INT PRIMARY KEY,
  name VARCHAR(50),
  class VARCHAR(10),
  city VARCHAR(30)
);

INSERT INTO students VALUES
(1, 'Aarav Sharma', '10A', 'Delhi'),
(2, 'Diya Iyer', '9B', 'Chennai'),
(3, 'Sneha Patil', '10A', 'Pune'),
(4, 'Mehul Agarwal', '9B', 'Delhi'),
(5, 'Saira Bano', '8C', 'Hyderabad');

SQL · portable concepts; preserved examples identify their engine

Let’s create an index on the city column since we often search students by city:

CREATE INDEX idx_city
ON students(city);

2. Query with Index Usage

Create this fresh input before the example below. The fixture belongs to this section, so its result does not depend on visiting another section first.

CREATE TABLE students (
  roll_no INT PRIMARY KEY,
  name VARCHAR(50),
  class VARCHAR(10),
  city VARCHAR(30)
);

INSERT INTO students VALUES
(1, 'Aarav Sharma', '10A', 'Delhi'),
(2, 'Diya Iyer', '9B', 'Chennai'),
(3, 'Sneha Patil', '10A', 'Pune'),
(4, 'Mehul Agarwal', '9B', 'Delhi'),
(5, 'Saira Bano', '8C', 'Hyderabad');

CREATE INDEX idx_city
ON students(city);

SQL · portable concepts; preserved examples identify their engine

The index supplies a possible access path. Inspect EXPLAIN and measure representative data to learn whether this query uses it and benefits from it.:

SELECT name, class
FROM students
WHERE city = 'Delhi';
name           | class
----------------+-------
Aarav Sharma   | 10A
Mehul Agarwal  | 9B

3. Composite Index (Multiple Columns)

Create this fresh input before the example below. The fixture belongs to this section, so its result does not depend on visiting another section first.

CREATE TABLE students (
  roll_no INT PRIMARY KEY,
  name VARCHAR(50),
  class VARCHAR(10),
  city VARCHAR(30)
);

INSERT INTO students VALUES
(1, 'Aarav Sharma', '10A', 'Delhi'),
(2, 'Diya Iyer', '9B', 'Chennai'),
(3, 'Sneha Patil', '10A', 'Pune'),
(4, 'Mehul Agarwal', '9B', 'Delhi'),
(5, 'Saira Bano', '8C', 'Hyderabad');

CREATE INDEX idx_city
ON students(city);

SQL · portable concepts; preserved examples identify their engine

Create an index on both class and city for combined filters:

CREATE INDEX idx_class_city
ON students(class, city);

This helps with queries like:

SELECT name
FROM students
WHERE class = '9B' AND city = 'Delhi';
name
----------
Mehul Agarwal

4. Unique Index

Create this fresh input before the example below. The fixture belongs to this section, so its result does not depend on visiting another section first.

CREATE TABLE students (
  roll_no INT PRIMARY KEY,
  name VARCHAR(50),
  class VARCHAR(10),
  city VARCHAR(30)
);

INSERT INTO students VALUES
(1, 'Aarav Sharma', '10A', 'Delhi'),
(2, 'Diya Iyer', '9B', 'Chennai'),
(3, 'Sneha Patil', '10A', 'Pune'),
(4, 'Mehul Agarwal', '9B', 'Delhi'),
(5, 'Saira Bano', '8C', 'Hyderabad');

CREATE INDEX idx_city
ON students(city);
CREATE INDEX idx_class_city
ON students(class, city);

SQL · portable concepts; preserved examples identify their engine

Indexes can also enforce uniqueness (aside from primary keys):

CREATE UNIQUE INDEX idx_unique_name
ON students(name);

This prevents duplicate names (useful if names must be unique in your context).

5. Drop an Index

Create this fresh input before the example below. The fixture belongs to this section, so its result does not depend on visiting another section first.

CREATE TABLE students (
  roll_no INT PRIMARY KEY,
  name VARCHAR(50),
  class VARCHAR(10),
  city VARCHAR(30)
);

INSERT INTO students VALUES
(1, 'Aarav Sharma', '10A', 'Delhi'),
(2, 'Diya Iyer', '9B', 'Chennai'),
(3, 'Sneha Patil', '10A', 'Pune'),
(4, 'Mehul Agarwal', '9B', 'Delhi'),
(5, 'Saira Bano', '8C', 'Hyderabad');

CREATE INDEX idx_city
ON students(city);
CREATE INDEX idx_class_city
ON students(class, city);
CREATE UNIQUE INDEX idx_unique_name
ON students(name);

Dialect distinction: the preserved DROP INDEX idx_city; form works in SQLite and PostgreSQL. On MySQL 8.4, use DROP INDEX idx_city ON students;. The index is recreated in the setup above before either drop variant is attempted.

SQL · portable concepts; preserved examples identify their engine

DROP INDEX idx_city;

Important Notes

  • Indexes improve SELECT performance, but slow down INSERT/UPDATE/DELETE a bit.
  • Use only where needed — don’t blindly index every column.
  • Use EXPLAIN (in MySQL/PostgreSQL) to see if your index is being used.

Real-World School Use Case

The school admin needs to quickly list students by city and class — indexing those columns speeds up daily reporting, especially when thousands of students are enrolled.

Important differences and mistakes

Indexes use storage and add work to writes. A low-selectivity filter or tiny table may make a scan a good choice. Index existence does not prove usage; inspect the engine’s execution plan and measure representative workloads.

Try it with the school data

Create a city index and read the Pune students. What should change about the logical answer?

This practice uses a separate, fresh fixture named practice_students. It does not continue the changing table state of the earlier examples.

Practice input: practice_students
roll_nonameclassmarkscity
1Aarav10A85Pune
2Diya9B70Chennai
3Sneha10A85Pune

SQL · create only these practice tables in a disposable database:

CREATE TABLE practice_students (roll_no INTEGER PRIMARY KEY, name VARCHAR(50), class VARCHAR(10), marks INTEGER, city VARCHAR(30));
INSERT INTO practice_students VALUES
(1, 'Aarav', '10A', 85, 'Pune'),
(2, 'Diya', '9B', 70, 'Chennai'),
(3, 'Sneha', '10A', 85, 'Pune');

Worked answer and reasoning

This practice uses a separate, fresh fixture named practice_students. It does not continue the changing table state of the earlier examples.

Practice input: practice_students
roll_nonameclassmarkscity
1Aarav10A85Pune
2Diya9B70Chennai
3Sneha10A85Pune

SQL · create only these practice tables in a disposable database:

CREATE TABLE practice_students (roll_no INTEGER PRIMARY KEY, name VARCHAR(50), class VARCHAR(10), marks INTEGER, city VARCHAR(30));
INSERT INTO practice_students VALUES
(1, 'Aarav', '10A', 85, 'Pune'),
(2, 'Diya', '9B', 70, 'Chennai'),
(3, 'Sneha', '10A', 85, 'Pune');

SQL · this practice variation runs with SQLite 3; the preserved examples retain their stated dialect

CREATE INDEX practice_city_index ON practice_students(city);
SELECT name FROM practice_students WHERE city = 'Pune' ORDER BY roll_no;
Expected query result
name
Aarav
Sneha

The index offers a possible access path. It must not change which city values match or which names are logically returned.

Check your understanding

Does adding an index guarantee that the engine uses it?
Choose one answer. You can try again.

Answer and explanation

No. The optimizer compares available access paths.

The index offers a possible access path. It must not change which city values match or which names are logically returned.

Use the idea independently

An index is an additional data structure that can help a database locate or order matching records. The optimizer decides whether using it is worthwhile for a query.

The index offers a possible access path. It must not change which city values match or which names are logically returned.

Continue your understanding with Read Execution Plans and Choose Effective Indexes.

Source for the engine-specific behavior: MySQL 8.4 reference documentation.

Reaching the recap and completing the quizzes are separate milestones.

    Next lesson: SQL Constraints — Enforcing Rules at the Table Level →