PostgreSQL 索引优化

PostgreSQLBeginner
立即练习

介绍

在本实验中,你将学习如何通过索引优化 PostgreSQL 数据库性能。你将首先创建一个示例 users 表并填充数据。然后,你将创建一个单列索引,使用 EXPLAIN 分析查询计划,构建一个多列索引,最后学习如何移除未使用的索引以保持数据库效率。这种实践经验将为你提供 PostgreSQL 索引管理的实用技能。

这是一个实验(Guided Lab),提供逐步指导来帮助你学习和实践。请仔细按照说明完成每个步骤,获得实际操作经验。根据历史数据,这是一个 初级 级别的实验,完成率为 97%。获得了学习者 98% 的好评率。

创建单列索引

在此步骤中,你将创建一个名为 users 的示例表,然后为 email 列创建一个单列索引。索引对于提高数据库查询性能至关重要,尤其是在处理大型表时。

首先,以 postgres 用户连接到 PostgreSQL 数据库:

sudo -u postgres psql

现在,创建 users 表。执行以下 SQL 命令:

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    username VARCHAR(50),
    email VARCHAR(100),
    created_at TIMESTAMP
);

此命令创建一个名为 users 的表,其中包含 idusernameemailcreated_at 列。id 列是主键,会自动递增。

接下来,向 users 表插入一些示例数据。执行以下 SQL 命令:

INSERT INTO users (username, email, created_at) VALUES
('john_doe', 'john.doe@example.com', NOW()),
('jane_smith', 'jane.smith@example.com', NOW()),
('peter_jones', 'peter.jones@example.com', NOW()),
('mary_brown', 'mary.brown@example.com', NOW()),
('alice_wilson', 'alice.wilson@example.com', NOW()),
('bob_davis', 'bob.davis@example.com', NOW()),
('carol_garcia', 'carol.garcia@example.com', NOW()),
('david_martinez', 'david.martinez@example.com', NOW()),
('emma_anderson', 'emma.anderson@example.com', NOW()),
('frank_taylor', 'frank.taylor@example.com', NOW());

-- Insert additional rows to make the table large enough for index usage
INSERT INTO users (username, email, created_at)
SELECT
    'user_' || generate_series(1, 1000),
    'user' || generate_series(1, 1000) || '@example.com',
    NOW();

你现在已经向 users 表插入了超过 1000 行数据。这个更大的数据集将有助于更有效地演示索引的使用,因为 PostgreSQL 通常会在索引比扫描整个表提供性能优势时使用索引。

为了加速基于 email 列的查询,请在 email 列上创建一个索引。执行以下 SQL 命令:

CREATE INDEX idx_users_email ON users (email);

此命令在 users 表的 email 列上创建一个名为 idx_users_email 的索引。

要验证索引是否已创建,你可以在 psql 中使用 \di 命令。执行以下命令:

\di

你应该会在输出中看到 idx_users_email 索引。

最后,通过输入以下命令退出 psql shell:

\q

使用 EXPLAIN 分析查询计划

在此步骤中,你将学习如何在 PostgreSQL 中使用 EXPLAIN 命令来分析查询计划。理解查询计划对于优化数据库查询和确保高效性能至关重要。

首先,以 postgres 用户连接到 PostgreSQL 数据库:

sudo -u postgres psql

现在,让我们使用 EXPLAIN 命令来分析一个简单的查询。执行以下命令:

EXPLAIN SELECT * FROM users WHERE email = 'jane.smith@example.com';

此命令将显示 SELECT 语句的查询计划。对于我们的大型数据集,你应该会在输出中看到“Index Scan”或“Bitmap Index Scan”,这表明 PostgreSQL 正在使用 idx_users_email 索引来高效地定位具有特定电子邮件地址的行。

要获取更详细的信息,包括成本,你可以使用 EXPLAIN ANALYZE。但是,对于这个基本示例,EXPLAIN 就足够了。

现在,让我们分析一个不使用 email 索引的查询。执行以下命令:

EXPLAIN SELECT * FROM users WHERE username LIKE 'user_%';

输出将显示对 users 表的“Seq Scan”(顺序扫描),这意味着 PostgreSQL 正在扫描整个表以查找匹配的行。发生这种情况是因为:

  1. 我们没有在 username 列上创建索引
  2. 结尾带有通配符的 LIKE 操作符可以从索引中受益,但如果没有索引,PostgreSQL 必须扫描所有行

这证明了在经常用于 WHERE 子句的列上创建索引的重要性。

通过使用 EXPLAIN 分析查询计划,你可以识别潜在的性能瓶颈,并确定你的索引是否被有效使用。

最后,通过输入以下命令退出 psql shell:

\q

创建多列索引

在此步骤中,你将学习如何在 PostgreSQL 中创建多列索引。多列索引是指包含两个或多个列的索引。当查询同时按多个列进行过滤或排序时,它可以显著提高查询性能。

首先,以 postgres 用户连接到 PostgreSQL 数据库:

sudo -u postgres psql

假设你经常根据 usernameemail 列查询 users 表。为了优化这些查询,你可以在这两个列上创建多列索引。执行以下 SQL 命令:

CREATE INDEX idx_users_username_email ON users (username, email);

此命令在 users 表的 usernameemail 列上创建了一个名为 idx_users_username_email 的索引。索引定义中列的顺序很重要。当查询按索引中出现的相同顺序过滤列时,索引的效果最好。

要验证索引是否已创建,你可以在 psql 中使用 \di 命令。执行以下命令:

\di

你应该会在输出中看到 idx_users_username_email 索引。

现在,让我们分析一个可以从这个多列索引中受益的查询。执行以下命令:

EXPLAIN SELECT * FROM users WHERE username = 'user_1' AND email = 'user1@example.com';

输出应该显示 PostgreSQL 正在使用 idx_users_username_email 索引来高效地执行查询。你应该在查询计划中看到“Index Scan”或“Bitmap Index Scan”,这表明多列索引正在被使用。

最后,通过输入以下命令退出 psql shell:

\q

删除未使用的索引

在此步骤中,你将学习如何在 PostgreSQL 中删除未使用的索引。索引可以提高查询性能,但它们也会占用存储空间,并可能减慢写入操作(插入、更新和删除)的速度。因此,识别并删除不再使用的索引非常重要。

首先,以 postgres 用户连接到 PostgreSQL 数据库:

sudo -u postgres psql

假设在分析你的查询模式后,你确定 idx_users_email 索引很少被使用。要删除此索引,请执行以下 SQL 命令:

DROP INDEX idx_users_email;

此命令将从数据库中删除名为 idx_users_email 的索引。

要验证索引是否已被删除,你可以在 psql 中使用 \di 命令。执行以下命令:

\di

你应该不再在输出中看到 idx_users_email 索引。

在删除索引之前,确保它确实未使用至关重要。你可以使用 PostgreSQL 的统计信息收集器来收集有关索引使用情况的信息。但是,启用和分析这些统计信息超出了本实验的范围。在实际场景中,你会在决定删除索引之前,先监控一段时间的索引使用情况。

注意:PostgreSQL 的查询规划器非常智能,并且仅在索引能带来性能优势时才会使用它们。对于非常小的表(通常少于几百行),PostgreSQL 可能会选择顺序扫描而不是索引扫描,因为使用索引的开销超过了其带来的好处。这就是我们向 users 表添加了许多行——为了演示真实的索引使用场景。

删除错误的索引可能会对查询性能产生负面影响。因此,请谨慎操作,并在删除任何索引之前彻底分析你的查询模式。

最后,通过输入以下命令退出 psql shell:

\q

总结

在本实验中,你学习了如何在 PostgreSQL 中创建单列和多列索引以提高查询性能。你还学习了如何使用 EXPLAIN 分析查询计划,以确定你的索引是否被有效使用。主要收获包括:

  • PostgreSQL 的查询规划器会根据表大小和查询特性智能地选择是否使用索引
  • 索引对于大型表最有益,因为索引查找的成本低于扫描所有行
  • 多列索引可以显著提高过滤多个列的查询的性能
  • 定期监控和删除未使用的索引有助于保持数据库的最佳性能

这些技能对于在实际应用中优化 PostgreSQL 数据库性能至关重要。