5.PG基础之索引

索引介绍

索引是数据库中的一种快速查询数据的方法。索引中记录了表中的一列或多列值与其物理位置之间的对应关系,就好比是一本书前面的目录,通过目录中页码就能快速定位到我们需要查询的内容。

索引的代价

  • 增加了数据库的存储空间
  • 在插入和修改数据时要花费较多的时间,因为索引也要随之更新

索引其他用途

除了加快查询以外,比如唯一索引还可以起到唯一约束的作用。


索引的分类

  1. BTree:最常用的索引,适合用于处理等值查询和范围查询。
  2. HASH:只能处理简单的等值查询。
  3. GiST:不是单独一种索引类型,而是一种架构,可以在这种架构上实现很多不同的索引策略。
  4. SP-GiST:即空间分区 GiST 索引,PostgreSQL 9.2 引入。
  5. GIN:反转索引,可以处理包含多个键的值。

创建索引

案例表结构

sql 复制代码
CREATE TABLE contacts (
    id int PRIMARY KEY,
    name varchar(40),
    phone varchar(32)[],
    address text
);

1. 简单 BTree 索引

为了实现按姓名 name 快速查询,可以在字段 name 上建一个 BTree 索引:

sql 复制代码
CREATE INDEX idx_contacts_name ON contacts(name);

2. GIN 索引(用于数组字段)

如果想按电话号码 phone 字段做快速查询(例如查询某个电话号码是谁的),由于此字段是一个数组,BTree 索引不再适用,可以建一个 GIN 索引:

sql 复制代码
CREATE INDEX idx_contacts_phone ON contacts USING gin(phone);

查询示例:

sql 复制代码
SELECT * FROM contacts WHERE phone @> ARRAY['13422334455'::varchar(32)];

解释:@> 是数组操作符,表示"包含"的意思,GIN 索引能在 @> 上起作用。


创建索引时带参数

sql 复制代码
CREATE INDEX idx_contacts_name ON contacts(name) WITH (FILLFACTOR=50);

按降序创建索引

sql 复制代码
CREATE INDEX idx_contacts_name ON contacts(name DESC);

指定空值排序

sql 复制代码
-- 空值排在非空值前面
CREATE INDEX idx_contacts_name ON contacts(name DESC NULLS FIRST);

-- 空值排在非空值后面
CREATE INDEX idx_contacts_name ON contacts(name DESC NULLS LAST);

并发创建索引

默认方式的问题

默认情况下,创建索引时会锁定表以防止写入,然后对表做全表扫描。在此过程中:

  • 其他用户可以读取表
  • 插入、更新、删除等操作将一直被阻塞,直到索引创建完毕

示例

sql 复制代码
CREATE TABLE testtab01 (id int PRIMARY KEY, note int);
INSERT INTO testtab01 SELECT generate_series(1,5000000), generate_series(1,5000000);

在一个窗口中创建索引:

sql 复制代码
CREATE INDEX idx_testtab01_note ON testtab01(note);

在另一个窗口中执行删除操作将被阻塞:

sql 复制代码
DELETE FROM testtab01 WHERE id=1;

使用 CONCURRENTLY 选项创建索引

这种方式不会长时间阻塞 DML 操作,但耗时更长,因为需要两次扫描表。

示例

sql 复制代码
DROP INDEX IF EXISTS idx_testtab01_note;
CREATE INDEX CONCURRENTLY idx_testtab01_note ON testtab01(note);

另一个窗口的删除语句可以正常执行:

sql 复制代码
DELETE FROM testtab01 WHERE id=2;
DELETE FROM testtab01 WHERE id=3;

并发创建索引的"坑"

如果在并发创建索引过程中取消操作,可能会导致索引残留(状态为 INVALID)。

处理方法

sql 复制代码
-- 查看表结构,确认无效索引
\d testtab01

-- 手动删除无效索引
DROP INDEX idx_testtab01_note;

修改索引

重命名索引

sql 复制代码
ALTER INDEX idx_contacts_name RENAME TO idx_contacts_name_old;

移动索引到指定表空间

sql 复制代码
ALTER INDEX idx_contacts_name_old SET TABLESPACE tbs_data01;

修改填充因子

sql 复制代码
ALTER INDEX idx_contacts_name_old SET (fillfactor = 75);

查看索引信息

sql 复制代码
\d+ idx_contacts_name_old

删除索引

安全删除(存在才删除)

sql 复制代码
DROP INDEX IF EXISTS idx_contacts_name_old;

默认 RESTRICT 行为

如果有对象依赖该索引,删除会失败。

示例

sql 复制代码
CREATE TABLE class (
    class_no int,
    class_name varchar(40)
);
CREATE UNIQUE INDEX index_unique_class_no ON class(class_no);

CREATE TABLE student (
    student_no int PRIMARY KEY,
    student_name varchar(40),
    age int,
    class_no int REFERENCES class(class_no)
);

-- 删除索引会失败,因为有外键依赖
DROP INDEX index_unique_class_no;

使用 CASCADE 强制删除

sql 复制代码
DROP INDEX index_unique_class_no CASCADE;

注意:使用 CASCADE 会同时删除依赖该索引的外键约束。


相关推荐
东风微鸣4 小时前
一次断电引发的血案:Ubuntu 26.04 升级中断后的完整救援实录
数据库·ubuntu·postgresql
ly76895 小时前
PostgreSQL JSONB 在 Spring Boot 中的读写边界:从 JDBC 类型映射到 GIN 索引失效
spring boot·postgresql·gin·jsonb·pgjdbc·gin 索引
小小龙学IT7 小时前
PostgreSQL 服务端机制与 SQL 实战深度解析:从 MVCC 到查询优化器
数据库·sql·postgresql
IvorySQL9 小时前
PostgreSQL 日报| pg_vectorsearch 开源向量搜索发布(10 月 14 日)
数据库·人工智能·postgresql·开源·区块链
xian_wwq9 小时前
【学习笔记】pgvector 入门:用 PostgreSQL 直接实现向量检索-13
笔记·学习·postgresql
岳麓丹枫00111 小时前
故障案例分析:系统负载居高不下,多次出现 OOM
linux·postgresql
IvorySQL1 天前
从轮询到等待——PostgreSQL WAIT FOR LSN 特性深度解析
数据库·postgresql
IvorySQL1 天前
PostgreSQL 日报|堆表选择性索引更新(10 月 13 日)
数据库·人工智能·postgresql·开源·区块链
ss2731 天前
PG实战笔记 | 06 PostgreSQL基础安装部署:Linux/Windows/macOS全攻略
linux·笔记·postgresql
行者-全栈开发1 天前
【码动四季·秋】基于开源做发行版:MySQL/PostgreSQL 国产化发行版的技术路径与选型实战
postgresql·开源数据库·opengauss·选型·国产化替代