MySQL Indexes and Performance Optimization

MySQLMySQLBeginner
Practice Now

Introduction

In this lab, you will learn about MySQL indexes and performance optimization techniques. The lab focuses on creating and managing indexes to improve database query performance.

You will start by creating a users table and inserting sample data. Then, you'll create a single-column index on the username column and learn how to verify its creation. The lab will also cover analyzing query plans using EXPLAIN, adding composite indexes for multi-column queries, and removing unused indexes to maintain database efficiency.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL mysql(("MySQL")) -.-> mysql/BasicKeywordsandStatementsGroup(["Basic Keywords and Statements"]) mysql(("MySQL")) -.-> mysql/AdvancedQueryingandOptimizationGroup(["Advanced Querying and Optimization"]) mysql(("MySQL")) -.-> mysql/SystemManagementToolsGroup(["System Management Tools"]) mysql/BasicKeywordsandStatementsGroup -.-> mysql/create_table("Table Creation") mysql/BasicKeywordsandStatementsGroup -.-> mysql/drop_table("Table Removal") mysql/BasicKeywordsandStatementsGroup -.-> mysql/alter_table("Table Modification") mysql/BasicKeywordsandStatementsGroup -.-> mysql/select("Data Retrieval") mysql/BasicKeywordsandStatementsGroup -.-> mysql/insert("Data Insertion") mysql/AdvancedQueryingandOptimizationGroup -.-> mysql/index("Index Management") mysql/SystemManagementToolsGroup -.-> mysql/show_status("Status Overview") subgraph Lab Skills mysql/create_table -.-> lab-550910{{"MySQL Indexes and Performance Optimization"}} mysql/drop_table -.-> lab-550910{{"MySQL Indexes and Performance Optimization"}} mysql/alter_table -.-> lab-550910{{"MySQL Indexes and Performance Optimization"}} mysql/select -.-> lab-550910{{"MySQL Indexes and Performance Optimization"}} mysql/insert -.-> lab-550910{{"MySQL Indexes and Performance Optimization"}} mysql/index -.-> lab-550910{{"MySQL Indexes and Performance Optimization"}} mysql/show_status -.-> lab-550910{{"MySQL Indexes and Performance Optimization"}} end

Create a Single-Column Index on a Table

In this step, you will learn how to create a single-column index in MySQL. Indexes are crucial for improving the performance of database queries, especially when dealing with large tables. An index on a column allows the database to quickly locate rows that match a specific value in that column, without having to scan the entire table.

Understanding Indexes

Think of an index like the index in a book. Instead of reading the entire book to find a specific topic, you can use the index to quickly locate the relevant pages. Similarly, a database index helps the database engine find specific rows quickly.

Creating a Table

First, let's create a simple table named users to demonstrate the creation of an index. Open a terminal in the LabEx VM. You can use the Xfce Terminal shortcut on the desktop.

Connect to the MySQL server as the root user:

mysql -u root -proot

Now, create the users table:

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(255) NOT NULL,
    email VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

This SQL statement creates a table named users with columns for id, username, email, and created_at. The id column is set as the primary key and auto-increments.

Let's insert some sample data into the users table:

INSERT INTO users (username, email) VALUES
('john_doe', '[email protected]'),
('jane_smith', '[email protected]'),
('peter_jones', '[email protected]');

Creating a Single-Column Index

Now, let's create an index on the username column. This will help speed up queries that search for users by their username.

CREATE INDEX idx_username ON users (username);

This statement creates an index named idx_username on the username column of the users table.

Verifying the Index

You can verify that the index has been created by using the SHOW INDEXES command:

SHOW INDEXES FROM users;

The output will show the details of the indexes on the users table, including the idx_username index you just created. You should see a row where Key_name is idx_username and Column_name is username.

+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name     | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| users |          0 | PRIMARY      |            1 | id          | A         |           3 |     NULL | NULL   |      | BTREE      |         |               | YES     | NULL       |
| users |          1 | idx_username |            1 | username    | A         |           3 |     NULL | NULL   |      | BTREE      |         |               | YES     | NULL       |
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+

Using the Index

To see the benefit of the index, you can use the EXPLAIN command to analyze a query that uses the username column. We will cover EXPLAIN in more detail in the next step, but for now, let's see a quick example.

EXPLAIN SELECT * FROM users WHERE username = 'john_doe';

The EXPLAIN output will show that the query is using the idx_username index, which means the database can quickly find the matching row without scanning the entire table. Look for possible_keys and key columns in the output. If the index is being used, you will see idx_username in these columns.

You have now successfully created a single-column index on a table. This will improve the performance of queries that filter data based on the indexed column.

exit;

Analyze a Query Plan Using EXPLAIN

In this step, you will learn how to use the EXPLAIN statement in MySQL to analyze the query execution plan. Understanding the query plan is essential for identifying performance bottlenecks and optimizing your queries.

What is a Query Plan?

A query plan is a roadmap that the database engine uses to execute a query. It describes the order in which tables are accessed, the indexes that are used, and the algorithms that are applied to retrieve the data. By analyzing the query plan, you can understand how the database is executing your query and identify areas for improvement.

Using the EXPLAIN Statement

The EXPLAIN statement provides information about how MySQL executes a query. It shows the tables involved, the indexes used, the join order, and other details that can help you understand the query's performance.

Let's continue using the users table we created in the previous step. Open a terminal in the LabEx VM (using the Xfce Terminal shortcut on the desktop) and connect to the MySQL server as the root user:

mysql -u root -proot

Now, let's analyze a simple query using EXPLAIN.

EXPLAIN SELECT * FROM users WHERE username = 'john_doe';

The output of the EXPLAIN statement will be a table with several columns. Here's a breakdown of some of the most important columns:

  • id: The ID of the SELECT statement.
  • select_type: The type of SELECT query (e.g., SIMPLE, PRIMARY, SUBQUERY).
  • table: The table being accessed.
  • type: The join type. This is one of the most important columns. Common values include:
    • system: The table has only one row.
    • const: The table has at most one matching row, which is read at the start of the query.
    • eq_ref: One row is read from this table for each combination of rows from the previous tables. This is used when joining on an indexed column.
    • ref: All matching rows are read from this table for each combination of rows from the previous tables. This is used when joining on an indexed column.
    • range: Only rows within a given range are retrieved, using an index.
    • index: A full index scan is performed.
    • ALL: A full table scan is performed. This is the least efficient type.
  • possible_keys: The indexes that MySQL could use to find the rows in the table.
  • key: The index that MySQL actually used.
  • key_len: The length of the key that MySQL used.
  • ref: The columns or constants that are compared to the index.
  • rows: The number of rows that MySQL estimates it will have to examine to execute the query.
  • Extra: Additional information about how MySQL is executing the query. Common values include:
    • Using index: The query can be satisfied using only the index.
    • Using where: MySQL needs to filter the rows after accessing the table.
    • Using temporary: MySQL needs to create a temporary table to execute the query.
    • Using filesort: MySQL needs to sort the rows after accessing the table.

Interpreting the EXPLAIN Output

For the query SELECT * FROM users WHERE username = 'john_doe', the EXPLAIN output should look something like this:

+----+-------------+-------+------------+------+---------------+--------------+---------+-------+------+-------+-------+
| id | select_type | table | partitions | type | possible_keys | key          | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+--------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | users | NULL       | ref  | idx_username  | idx_username | 767     | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+--------------+---------+-------+------+----------+-------+

In this example:

  • type is ref, which means that MySQL is using an index to find the matching row.
  • possible_keys and key both show idx_username, which means that MySQL is using the idx_username index that we created in the previous step.
  • rows is 1, which means that MySQL estimates it will have to examine only one row to execute the query.

Analyzing a Query Without an Index

Now, let's analyze a query that does not use an index. First, let's add a new column to the users table called city:

ALTER TABLE users ADD COLUMN city VARCHAR(255);

Now, let's run an EXPLAIN on a query that searches by city:

EXPLAIN SELECT * FROM users WHERE city = 'New York';

Since we haven't added any data to the city column, let's update one of the rows:

UPDATE users SET city = 'New York' WHERE username = 'john_doe';

Now, run the EXPLAIN statement again:

EXPLAIN SELECT * FROM users WHERE city = 'New York';

The output might look like this:

+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | users | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |    33.33 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+

In this example:

  • type is ALL, which means that MySQL is performing a full table scan.
  • possible_keys and key are both NULL, which means that MySQL is not using any indexes.
  • rows is 3, which means that MySQL estimates it will have to examine all 3 rows in the table to execute the query.
  • Extra shows Using where, which means that MySQL needs to filter the rows after accessing the table.

This indicates that the query is not optimized and could benefit from an index on the city column.

exit;

Add a Composite Index for Multi-Column Queries

In this step, you will learn how to create a composite index in MySQL. A composite index is an index on two or more columns in a table. It can significantly improve the performance of queries that filter data based on multiple columns.

What is a Composite Index?

A composite index is an index that covers multiple columns. It is useful when queries frequently use multiple columns in the WHERE clause. The order of columns in the composite index is important. The index is most effective when the columns are specified in the same order in the query's WHERE clause.

Let's continue using the users table we created in the previous steps. Open a terminal in the LabEx VM (using the Xfce Terminal shortcut on the desktop) and connect to the MySQL server as the root user:

mysql -u root -proot

Let's add some more data to the users table, including different cities:

INSERT INTO users (username, email, city) VALUES
('alice_brown', '[email protected]', 'Los Angeles'),
('bob_davis', '[email protected]', 'Chicago'),
('charlie_wilson', '[email protected]', 'New York'),
('david_garcia', '[email protected]', 'Los Angeles');

Creating a Composite Index

Suppose you often run queries that filter users by both city and username. In this case, you can create a composite index on the city and username columns.

CREATE INDEX idx_city_username ON users (city, username);

This statement creates an index named idx_city_username on the city and username columns of the users table.

Verifying the Index

You can verify that the index has been created by using the SHOW INDEXES command:

SHOW INDEXES FROM users;

The output will show the details of the indexes on the users table, including the idx_city_username index you just created. You should see two rows for idx_city_username, one for the city column and one for the username column.

+-------+------------+-------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name          | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+-------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| users |          0 | PRIMARY           |            1 | id          | A         |           7 |     NULL | NULL   |      | BTREE      |         |               | YES     | NULL       |
| users |          1 | idx_username      |            1 | username    | A         |           7 |     NULL | NULL   |      | BTREE      |         |               | YES     | NULL       |
| users |          1 | idx_city_username |            1 | city        | A         |           3 |     NULL | NULL   | YES  | BTREE      |         |               | YES     | NULL       |
| users |          1 | idx_city_username |            2 | username    | A         |           7 |     NULL | NULL   |      | BTREE      |         |               | YES     | NULL       |
+-------+------------+-------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+

Using the Composite Index

To see the benefit of the composite index, you can use the EXPLAIN command to analyze a query that uses both the city and username columns in the WHERE clause.

EXPLAIN SELECT * FROM users WHERE city = 'New York' AND username = 'charlie_wilson';

The EXPLAIN output will show that the query is using the idx_city_username index, which means the database can quickly find the matching row without scanning the entire table. Look for possible_keys and key columns in the output. If the index is being used, you will see idx_city_username in these columns.

+----+-------------+-------+------------+------+-------------------+-------------------+---------+-------------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys     | key               | key_len | ref         | rows | filtered | Extra |
+----+-------------+-------+------------+------+-------------------+-------------------+---------+-------------+------+----------+-------+
|  1 | SIMPLE      | users | NULL       | ref  | idx_city_username | idx_city_username | 770     | const,const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+-------------------+-------------------+---------+-------------+------+----------+-------+

Order of Columns in the Index

The order of columns in the composite index matters. If you create an index on (username, city) instead of (city, username), the index will be less effective for queries that filter by city and then username.

For example, if we had an index on (username, city) and ran the following query:

EXPLAIN SELECT * FROM users WHERE city = 'New York' AND username = 'charlie_wilson';

MySQL might not use the index, or it might only use it partially, because the city column is not the leading column in the index.

exit;

Remove an Unused Index

In this step, you will learn how to remove an unused index in MySQL. While indexes can significantly improve query performance, they also add overhead to write operations (inserts, updates, and deletes). Therefore, it's important to identify and remove indexes that are no longer being used.

Why Remove Unused Indexes?

Unused indexes take up disk space and can slow down write operations. When data is modified in a table, the database engine must also update all the indexes on that table. If an index is not being used by any queries, it's just adding unnecessary overhead.

Let's continue using the users table we created in the previous steps. Open a terminal in the LabEx VM (using the Xfce Terminal shortcut on the desktop) and connect to the MySQL server as the root user:

mysql -u root -proot

In the previous steps, we created an index named idx_username on the username column. Let's assume that, after analyzing your query patterns, you determine that this index is no longer being used.

Removing the Index

To remove the idx_username index, you can use the DROP INDEX statement:

DROP INDEX idx_username ON users;

This statement removes the idx_username index from the users table.

Verifying the Index Removal

You can verify that the index has been removed by using the SHOW INDEXES command:

SHOW INDEXES FROM users;

The output will show the details of the indexes on the users table. You should no longer see the idx_username index in the output.

+-------+------------+-------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name          | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+-------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| users |          0 | PRIMARY           |            1 | id          | A         |           7 |     NULL | NULL   |      | BTREE      |         |               | YES     | NULL       |
| users |          1 | idx_city_username |            1 | city        | A         |           3 |     NULL | NULL   | YES  | BTREE      |         |               | YES     | NULL       |
| users |          1 | idx_city_username |            2 | username    | A         |           7 |     NULL | NULL   |      | BTREE      |         |               | YES     | NULL       |
+-------+------------+-------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+

Identifying Unused Indexes

In a real-world scenario, identifying unused indexes can be challenging. MySQL provides several tools and techniques to help you with this task:

  • MySQL Enterprise Audit: This feature allows you to log all queries executed on your server. You can then analyze the query logs to identify which indexes are being used.
  • Performance Schema: The Performance Schema provides detailed information about server performance, including index usage.
  • Third-Party Tools: Several third-party tools can help you monitor index usage and identify unused indexes.

By regularly monitoring your index usage and removing unused indexes, you can improve the overall performance of your database.

exit;

Summary

In this lab, you learned how to create a single-column index in MySQL to improve query performance, especially for large tables. The process involved connecting to the MySQL server, creating a users table with columns for id, username, email, and created_at, and inserting sample data.

The key step was creating an index named idx_username on the username column using the CREATE INDEX statement. This index will speed up queries that search for users by their username, allowing the database to quickly locate rows matching specific username values without scanning the entire table.