CodeGym /Courses /SQL SELF /How to Choose the Right Index Type

How to Choose the Right Index Type

SQL SELF
Level 38 , Lesson 3
Available

We’ve already dived into index theory, checked out their types, learned how to create and drop them, and figured out how to index tricky data types like arrays and JSONB. Now it’s time to talk about how to pick the index that’ll actually work best for your use case—because picking the wrong one can cause some serious headaches.

Imagine your database is a library, and queries are visitors looking for books. If the books are just scattered all over the floor, finding anything turns into an endless wandering. Indexes are like organized shelves and catalogs that help you find what you need fast, without having to look through everything.

But if you set up the wrong shelf or catalog—like using a HASH index where you really need a range search index—it’s like the librarian trying to find books by title, but only having a catalog sorted by publication year. The process drags on, and everyone starts complaining. In your database, this means slow queries and extra load on the system.

Today we’ll break down how to pick the right index so your queries fly and your database doesn’t get tired. If you mess up, the result is ugly: slow queries, wasted resources, and the librarian (PostgreSQL) sitting in a funk.

Index Selection Criteria: Checklist

When you’re picking an index, ask yourself a few questions:

  1. What’s the data type in this column?
    • For example, numbers like INTEGER, FLOAT usually need a B-TREE index, arrays—GIN, text fields—it depends on the task.
  1. What queries do you run most often?

    • WHERE field = value? Direct lookup? You’ll probably want B-TREE or HASH.
    • Searching arrays or JSONB? Check out GIN.
    • Geo data, ranges? Think about GiST.
  2. What’s happening with your data?

    • If your table gets a lot of inserts and updates, avoid over-indexing, since that adds overhead.
  3. Do you need to enforce uniqueness?

    • In that case, you’ll need an index with the UNIQUE attribute.

Cases: Real-Life Index Selection Examples

Let’s check out a few real-world scenarios.

1. Simple Equality Search

You’re working with a student database and want to quickly find a student by their email:

SELECT * FROM students WHERE email = 'student@example.com';

What matters here? We’re searching by equality. The best choice is a B-TREE index, since it’s great for exact matches.

CREATE INDEX idx_students_email ON students (email);

Or, if email needs to be unique:

CREATE UNIQUE INDEX idx_students_email_unique ON students (email);

2. Range Search

Now let’s say you want to find students older than 18:

SELECT * FROM students WHERE age > 18;

For range searches, B-TREE is also a solid pick, since its structure is made for ordered lookups.

CREATE INDEX idx_students_age ON students (age);

3. Filtering by Arrays

You’ve got a courses table, where one column stores an array of student IDs enrolled in the course. You want to find all courses that student with ID 123 is enrolled in.

SELECT * FROM courses WHERE student_ids @> ARRAY[123];

For these queries, a GIN index is perfect, since it’s optimized for arrays.

CREATE INDEX idx_courses_students_ids ON courses USING gin (student_ids);

4. Extracting Data from JSONB

Let’s say you have a table with JSONB data storing order info. You want to find all orders where the client is from "Moscow":

SELECT * FROM orders WHERE data->>'city' = 'Moscow';

For this query a GIN index over the entire column is no help — the ->> operator isn't indexable via jsonb_ops/jsonb_path_ops. You need either an expression index on the specific key, or to rewrite the query with the @> operator:

-- Option 1: expression index
CREATE INDEX idx_orders_city ON orders ((data->>'city'));

-- Option 2: use @> with GIN
CREATE INDEX idx_orders_data ON orders USING gin (data);
SELECT * FROM orders WHERE data @> '{"city": "Moscow"}';

5. Geographic Data

If you’re working with geo info—like finding all points within a certain radius—use a GiST index. This index type is awesome for geometry and ranges.

CREATE INDEX idx_locations_geom ON locations USING gist (geom);

Performance Comparison of Different Indexes

Let’s take a real example: searching students by email. The table has 1 million rows. Exact numbers depend on the specific system and data distribution, but the order of magnitude is:

Scenario Execution Time
No index ~1500 ms
With B-TREE index ~2-3 ms
With HASH index ~1-2 ms

For strict equality (=) a HASH index is often slightly faster than B-TREE because it does an O(1) lookup versus O(log n) for B-TREE. However, B-TREE is more universal: it works not only for = but also for ranges, sorting, and LIKE with a prefix — so B-TREE remains the default choice.

Mistakes When Choosing Indexes

The most common mistake is creating indexes “just in case.” For example, you decide to index every column in your table, but then notice that insert performance tanks. Remember, an index isn’t a magic tool that always works everywhere. It’s a powerful tool in the right hands, but using it wrong can hurt.

Another classic mistake is picking the wrong index type. Say you use a HASH index for a range search, and your queries suddenly get super slow. That’s because HASH indexes are only good for exact lookups.

Index Selection Tips

  • If you often do equality searches or sorting, use B-TREE.
  • For exact matches with minimal memory, you can use HASH.
  • If you’re working with arrays or JSONB, go with GIN.
  • For ranges or geo data, use GiST.

And finally, the main tip: always analyze your queries! Use EXPLAIN and EXPLAIN ANALYZE to see how PostgreSQL uses indexes and what you can improve.

EXPLAIN ANALYZE
SELECT * FROM students WHERE email = 'student@example.com';

That’s it for today! Now you’re ready to pick indexes like a Jedi picks their lightsaber. Be careful, don’t create indexes where you don’t need them, and always check how they affect performance.

2
Task
SQL SELF, level 38, lesson 3
Locked
Using an Index for Range Search
Using an Index for Range Search
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION