Skip to content

Commit a59c663

Browse files
Adez017sanjay-kv
andcommitted
Added index page
Co-Authored-By: Sanjay Viswanathan <[email protected]>
1 parent eadefd5 commit a59c663

File tree

2 files changed

+371
-0
lines changed

2 files changed

+371
-0
lines changed
Lines changed: 370 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,370 @@
1+
---
2+
id: sql-indexes
3+
title: SQL Indexes - The Complete Guide
4+
sidebar_label: Indexes
5+
sidebar_position: 1
6+
tags:
7+
[
8+
sql,
9+
indexes,
10+
database indexes,
11+
performance,
12+
query optimization,
13+
b-tree,
14+
clustered index,
15+
non-clustered index,
16+
composite index,
17+
sql tutorial,
18+
]
19+
description: Master SQL Indexes with practical examples. Learn when to create indexes, types of indexes, optimization strategies, and common pitfalls to avoid.
20+
---
21+
Ever wondered why some SQL queries feel like they run in milliseconds while others take minutes on the same table?
22+
The secret often lies in how well your database uses indexes.
23+
Let’s explore how SQL indexes work and how you can use them to make your queries fly
24+
## What are SQL Indexes?
25+
26+
SQL **Indexes** are special database structures that dramatically speed up data retrieval operations. Think of them like an index in a book - instead of reading every page to find information, you can jump directly to the right page.
27+
28+
:::note
29+
**Key Characteristics of Indexes:**
30+
31+
- **Speed Up Queries**: Can make queries 10x, 100x, or even 1000x faster.
32+
33+
- **Cost of Storage**: Require additional disk space to store the index structure.
34+
35+
- **Write Overhead**: Slow down INSERT, UPDATE, and DELETE operations slightly.
36+
37+
- **Automatic Maintenance**: Database automatically updates indexes when data changes.
38+
:::
39+
<!--
40+
<BrowserWindow url="https://github.com" bodyStyle={{padding: 0}}>
41+
[![GitHub](./assets/indexes-concept.png)](https://www.learnsqlonline.org/)
42+
</BrowserWindow> -->
43+
44+
:::success
45+
**The Phone Book Analogy:**
46+
47+
Imagine searching for "John Smith" in a phone book:
48+
49+
**Without Index (Full Table Scan):** You'd have to read every single entry from page 1 to the end until you find John Smith. On a million-entry phone book, this is painfully slow.
50+
51+
**With Index:** The phone book is already sorted alphabetically (that's an index!). You can jump directly to the "S" section and find John Smith in seconds.
52+
53+
That's exactly what database indexes do - they organize data in a way that makes searches lightning-fast.
54+
55+
**Real-World Impact:**
56+
A query that takes 30 seconds on a million-row table without an index might complete in 0.01 seconds with the right index. That's a 3000x performance improvement!
57+
:::
58+
59+
:::info
60+
61+
## How Indexes Work Under the Hood
62+
63+
```sql
64+
-- Without index: Database scans every row
65+
SELECT * FROM employees WHERE employee_id = 12345;
66+
-- Scans: 1, 2, 3, 4, ... 12345 (sequential search)
67+
68+
-- With index: Database jumps directly to the row
69+
SELECT * FROM employees WHERE employee_id = 12345;
70+
-- Jump directly to: 12345 (index lookup)
71+
```
72+
73+
**Index Structure (Simplified B-Tree):**
74+
```
75+
[50]
76+
/ \
77+
[25] [75]
78+
/ \ / \
79+
[10] [40] [60] [90]
80+
```
81+
82+
The database traverses this tree structure to find values quickly. For a million rows, it might only need to check 20-30 nodes instead of a million rows!
83+
84+
| **Operation** | **Without Index** | **With Index** | **Improvement** |
85+
|---------------|-------------------|----------------|-----------------|
86+
| Find by ID | O(n) - Linear | O(log n) - Logarithmic | Exponential |
87+
| Range search | O(n) | O(log n + k) | Significant |
88+
| Sort | O(n log n) | O(n) or O(1) | Major |
89+
90+
:::
91+
92+
## Types of Indexes
93+
| Index Type | Description | Best Use Case |
94+
| ----------------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------- |
95+
| **Clustered Index** | Determines the physical order of data in the table. Each table can have only one. | Primary key columns. |
96+
| **Non-Clustered Index** | A separate structure that points to table data. | Columns used in WHERE, JOIN, ORDER BY. |
97+
| **Composite Index** | Index on multiple columns. | Queries filtering on multiple conditions. |
98+
| **Unique Index** | Prevents duplicate values in a column. | Email IDs, Usernames, etc. |
99+
| **Covering Index** | Includes all columns a query needs. | Read-heavy analytical queries. |
100+
| **Partial Index** | Indexes a subset of rows. | Filtering on frequently used conditions (e.g., active users). |
101+
| **Full-Text Index** | Optimized for text search. | Searching within text or document fields. |
102+
103+
104+
## Creating and Managing Indexes
105+
106+
:::tip
107+
**Creating Indexes - Syntax Variations**
108+
109+
```sql
110+
-- Basic syntax
111+
CREATE INDEX index_name ON table_name(column_name);
112+
113+
-- Multiple columns
114+
CREATE INDEX idx_name ON table_name(col1, col2, col3);
115+
116+
-- Unique index
117+
CREATE UNIQUE INDEX idx_name ON table_name(column_name);
118+
119+
-- With specific algorithm (MySQL)
120+
CREATE INDEX idx_name ON table_name(column_name) USING BTREE;
121+
CREATE INDEX idx_name ON table_name(column_name) USING HASH;
122+
123+
-- Descending order (useful for ORDER BY DESC queries)
124+
CREATE INDEX idx_name ON table_name(column_name DESC);
125+
126+
-- Conditional index (PostgreSQL)
127+
CREATE INDEX idx_name ON table_name(column_name) WHERE condition;
128+
129+
-- Concurrent creation (PostgreSQL - doesn't lock table)
130+
CREATE INDEX CONCURRENTLY idx_name ON table_name(column_name);
131+
132+
-- With included columns (SQL Server, PostgreSQL 11+)
133+
CREATE INDEX idx_name ON table_name(key_column)
134+
INCLUDE (non_key_column1, non_key_column2);
135+
```
136+
137+
**Dropping Indexes**
138+
139+
```sql
140+
-- Standard syntax
141+
DROP INDEX index_name ON table_name; -- MySQL
142+
DROP INDEX index_name; -- PostgreSQL
143+
144+
-- SQL Server
145+
DROP INDEX table_name.index_name;
146+
147+
-- Check if exists first
148+
DROP INDEX IF EXISTS index_name ON table_name;
149+
```
150+
151+
**Viewing Indexes**
152+
153+
```sql
154+
-- MySQL
155+
SHOW INDEXES FROM table_name;
156+
SHOW INDEX FROM table_name WHERE Key_name = 'idx_name';
157+
158+
-- PostgreSQL
159+
SELECT * FROM pg_indexes WHERE tablename = 'table_name';
160+
161+
-- SQL Server
162+
SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID('table_name');
163+
164+
-- Standard SQL (works on most databases)
165+
SELECT * FROM information_schema.statistics
166+
WHERE table_name = 'table_name';
167+
```
168+
:::
169+
170+
## When to Create Indexes
171+
172+
:::success
173+
**You SHOULD Create an Index When:**
174+
175+
**Frequently Used in WHERE Clauses**
176+
```sql
177+
-- If you run this query 1000 times per day:
178+
SELECT * FROM users WHERE email = '[email protected]';
179+
-- You NEED this index:
180+
CREATE INDEX idx_users_email ON users(email);
181+
```
182+
183+
**Used in JOIN Conditions**
184+
```sql
185+
-- Frequently joining these tables:
186+
SELECT o.*, c.customer_name
187+
FROM orders o
188+
JOIN customers c ON o.customer_id = c.customer_id;
189+
190+
-- Create indexes on join columns:
191+
CREATE INDEX idx_orders_customer_id ON orders(customer_id);
192+
CREATE INDEX idx_customers_id ON customers(customer_id); -- Often already exists as PK
193+
```
194+
195+
**Used in ORDER BY**
196+
```sql
197+
-- Common sorting pattern:
198+
SELECT * FROM products ORDER BY category, price DESC;
199+
-- Index helps:
200+
CREATE INDEX idx_products_category_price ON products(category, price DESC);
201+
```
202+
203+
**Used in GROUP BY**
204+
```sql
205+
-- Aggregation queries:
206+
SELECT department, COUNT(*)
207+
FROM employees
208+
GROUP BY department;
209+
-- Index helps:
210+
CREATE INDEX idx_employees_department ON employees(department);
211+
```
212+
213+
**Foreign Key Columns**
214+
```sql
215+
-- Always index foreign keys:
216+
ALTER TABLE orders ADD FOREIGN KEY (customer_id) REFERENCES customers(id);
217+
CREATE INDEX idx_orders_customer_id ON orders(customer_id);
218+
```
219+
220+
**Columns with High Selectivity**
221+
```sql
222+
-- High selectivity: email, SSN, username (unique or near-unique)
223+
CREATE INDEX idx_users_email ON users(email);
224+
225+
-- NOT low selectivity: gender, boolean flags, status with few values
226+
-- Don't index: gender (only 'M', 'F', 'Other')
227+
```
228+
:::
229+
230+
:::danger
231+
**You Should NOT Create an Index When:**
232+
233+
**Table is Small (< 1000 rows)**
234+
```sql
235+
-- Overhead of index > benefit for tiny tables
236+
-- Database can scan 1000 rows faster than using index
237+
```
238+
239+
**Column Has Low Selectivity**
240+
```sql
241+
-- Bad: is_active (only TRUE/FALSE values)
242+
-- Bad: gender (only 2-3 values)
243+
-- Bad: status (only 'active', 'inactive', 'pending')
244+
245+
-- Exception: If you're filtering 99% of data
246+
-- Partial index can help:
247+
CREATE INDEX idx_users_inactive ON users(last_login)
248+
WHERE is_active = FALSE; -- If only 1% are inactive
249+
```
250+
251+
**Column Frequently Updated**
252+
```sql
253+
-- Think twice before indexing columns that change often
254+
-- Example: 'last_updated', 'view_count', 'login_count'
255+
-- Every UPDATE must update the index too
256+
```
257+
258+
**Already Covered by Composite Index**
259+
```sql
260+
-- Existing index:
261+
CREATE INDEX idx_orders_customer_date ON orders(customer_id, order_date);
262+
263+
-- Redundant: customer_id is already indexed (leftmost column)
264+
CREATE INDEX idx_orders_customer ON orders(customer_id); -- ❌ Not needed
265+
266+
-- But this would be useful (different leftmost column):
267+
CREATE INDEX idx_orders_date_customer ON orders(order_date, customer_id); -- ✓ OK
268+
```
269+
270+
**Table Has Heavy Write Operations**
271+
```sql
272+
-- Logging tables, temporary staging tables
273+
-- If 90% operations are INSERT, minimize indexes
274+
-- Keep only essential ones
275+
```
276+
:::
277+
278+
## Practical Example
279+
```sql
280+
-- Before indexing
281+
SELECT * FROM employees WHERE department_id = 5;
282+
-- Took 2.8s (full table scan)
283+
284+
-- After indexing
285+
CREATE INDEX idx_department_id ON employees(department_id);
286+
SELECT * FROM employees WHERE department_id = 5;
287+
-- Took 0.03s (index scan)
288+
```
289+
> After indexing `department_id`, the query optimizer uses an index scan instead of a full table scan — drastically improving performance.
290+
## Common Indexing Mistakes
291+
292+
:::danger
293+
**Mistake #1: Over-Indexing**
294+
```sql
295+
-- Bad: Index every column "just in case"
296+
CREATE INDEX idx_users_email ON users(email);
297+
CREATE INDEX idx_users_first_name ON users(first_name);
298+
CREATE INDEX idx_users_last_name ON users(last_name);
299+
CREATE INDEX idx_users_phone ON users(phone);
300+
CREATE INDEX idx_users_address ON users(address);
301+
CREATE INDEX idx_users_city ON users(city);
302+
CREATE INDEX idx_users_state ON users(state);
303+
CREATE INDEX idx_users_zip ON users(zip);
304+
305+
-- Problems:
306+
-- ✗ Slows down INSERT/UPDATE/DELETE
307+
-- ✗ Wastes disk space
308+
-- ✗ Database has to choose between many indexes (confusion)
309+
310+
-- Good: Index only frequently queried columns
311+
CREATE UNIQUE INDEX idx_users_email ON users(email);
312+
CREATE INDEX idx_users_location ON users(state, city); -- Composite for location queries
313+
```
314+
315+
**Mistake #2: Wrong Column Order in Composite Index**
316+
```sql
317+
-- Query pattern:
318+
SELECT * FROM orders
319+
WHERE customer_id = 123 AND order_date >= '2024-01-01';
320+
321+
-- Bad: Date first (less selective)
322+
CREATE INDEX idx_orders_wrong ON orders(order_date, customer_id);
323+
324+
-- Good: Customer first (more selective, used in more queries)
325+
CREATE INDEX idx_orders_right ON orders(customer_id, order_date);
326+
```
327+
328+
**Mistake #3: Indexing Low-Cardinality Columns**
329+
```sql
330+
-- Bad: Only 2 values (M/F)
331+
CREATE INDEX idx_users_gender ON users(gender);
332+
333+
-- Bad: Only 3-4 values
334+
CREATE INDEX idx_orders_status ON orders(status);
335+
336+
-- Exception: OK if filtering out 99% of data
337+
CREATE INDEX idx_users_suspended
338+
ON users(last_login, email)
339+
WHERE is_suspended = TRUE; -- If only 0.1% are suspended
340+
```
341+
:::
342+
343+
## Conclusion
344+
SQL Indexes are one of the most powerful tools for **database performance optimization** — when used wisely. They can transform sluggish queries into lightning-fast ones, enabling your applications to scale efficiently and handle millions (or even billions) of rows seamlessly.
345+
346+
However, indexes are a **double-edged sword** — while they boost read performance, they come with tradeoffs in **storage cost, maintenance overhead, and slower write operations**. The key is balance: index only what’s necessary based on query patterns, selectivity, and workload characteristics.
347+
348+
## Key Takeaways:
349+
350+
- **Understand your queries first** — analyze WHERE, JOIN, ORDER BY, and GROUP BY clauses before creating indexes.
351+
352+
- **Use the right type of index** — primary, unique, composite, covering, partial, or full-text — depending on your use case.
353+
354+
- **Monitor and tune continuously** — use query planners and performance metrics (EXPLAIN, ANALYZE, SHOW INDEXES) to verify if indexes are being used effectively.
355+
356+
- **Avoid over-indexing** — every index adds write overhead. Drop unused or redundant ones regularly.
357+
358+
- **Think strategically** — use composite indexes following the left-to-right rule and leverage partial indexes for highly specific queries.
359+
360+
In essence, a well-designed indexing strategy is the foundation of a performant database system. By mastering when and how to use indexes, you’ll unlock the full potential of SQL — delivering faster queries, efficient storage, and a smoother user experience.
361+
362+
>🏁 Optimize smartly — not by adding more indexes, but by adding the right ones.
363+
364+
## Further Reading
365+
366+
- [PostgreSQL Indexing Documentation](https://www.postgresql.org/docs/current/indexes.html)
367+
368+
- [SQL Server Index Architecture and Design Guide](https://learn.microsoft.com/en-us/sql/relational-databases/sql-server-index-design-guide)
369+
370+
- [MySQL Index Optimization Tips](https://dev.mysql.com/doc/refman/8.0/en/mysql-indexes.html)

sidebars.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ const sidebars: SidebarsConfig = {
152152
'sql/SQL-Advance/sql-subqueries',
153153
'sql/SQL-Advance/common-table-expressions',
154154
'sql/SQL-Advance/window-functions',
155+
'sql/SQL-Advance/sql-indexes'
155156
],
156157
},
157158
],

0 commit comments

Comments
 (0)