PostgreSQL学习笔记

PostgreSQL 基本概念和架构

PostgreSQL 是一个功能强大的开源对象关系数据库管理系统(ORDBMS),其设计目标是遵循 SQL 标准,并提供丰富的功能,如复杂查询、外键、触发器、视图和事务处理。以下是 PostgreSQL 的基本概念和架构的详细介绍。

基本概念

对象关系型数据库

PostgreSQL 结合了关系型数据库和面向对象数据库的特性,支持关系型数据模型(表、行、列)以及面向对象的数据模型(继承、自定义类型)。

ACID 属性

PostgreSQL 支持 ACID(原子性、一致性、隔离性、持久性)属性,确保事务处理的可靠性和数据的一致性。

  • 原子性(Atomicity):事务中的所有操作要么全部完成,要么全部不完成。
  • 一致性(Consistency):事务从一个一致性状态转换到另一个一致性状态。
  • 隔离性(Isolation):事务之间的操作是隔离的,相互不可见。
  • 持久性(Durability):一旦事务提交,其结果是永久性的。
扩展性

PostgreSQL 支持用户自定义数据类型、函数、操作符、索引方法等,极大地增强了系统的灵活性和扩展能力。

标准兼容性

PostgreSQL 遵循 SQL 标准,并不断引入新特性和增强功能。

架构概述

PostgreSQL 的架构由多个层次和组件组成,各部分相互协作以提供高效的数据库服务。以下是其主要组件和架构层次:

1. 进程模型
主进程(Postmaster)
  • 管理数据库服务器的启动和关闭,处理客户端连接。
后台进程
  • 检查点进程(Checkpointer Process):负责将内存中的数据写入磁盘,确保数据的一致性。
  • 写入器进程(Writer Process):将脏页(修改过的数据页)写入磁盘。
  • 归档进程(Archiver Process):将 WAL 日志文件复制到存档位置。
  • 统计进程(Stats Collector Process):收集数据库的统计信息。
子进程
  • 每个客户端连接都会创建一个子进程,专门负责处理该连接的请求。
2. 存储层
表和索引
  • 数据存储在表中,索引用于加速查询。PostgreSQL 支持多种索引类型,如 B 树、哈希、GiST、GIN 等。
表空间
  • 用于管理物理存储位置,可以将不同的数据库对象存储在不同的表空间中,以提高性能和管理灵活性。
事务日志(WAL)
  • 用于记录所有事务操作,以确保数据的持久性和恢复能力。
3. 执行层
查询解析器(Parser)
  • 将 SQL 查询解析为语法树。
查询重写系统(Rewrite System)
  • 对语法树进行重写和优化,以生成更高效的执行计划。
查询优化器(Optimizer)
  • 选择最佳的执行计划,通过分析统计信息和代价估算,确定最优的查询路径。
执行引擎(Executor)
  • 根据优化器生成的执行计划,逐步执行查询操作,并返回结果。
4. 客户端接口
psql
  • PostgreSQL 提供的命令行工具,用于执行 SQL 命令和脚本。
pgAdmin
  • 图形化管理工具,方便用户进行数据库管理和开发工作。
驱动程序
  • 如 JDBC、ODBC、libpq 等,支持多种编程语言和开发环境,与数据库进行交互。

典型的数据库操作流程

  1. 连接和认证:客户端通过 libpq、JDBC、ODBC 或其他驱动连接到 PostgreSQL,Postmaster 进程接受连接请求并进行认证。
  2. SQL 解析:客户端发送 SQL 查询,Parser 将其解析为内部语法树结构。
  3. 查询重写和优化:Rewrite System 对语法树进行重写,Optimizer 生成最优执行计划。
  4. 执行计划:Executor 按照执行计划逐步执行查询操作,访问存储层的数据和索引。
  5. 结果返回:查询结果返回给客户端,统计信息更新,相关进程处理日志和缓存。

阅读官方文档的入门部分

要深入了解 PostgreSQL 的基本概念和架构,建议阅读官方文档中的以下章节:

  • Introduction:概述 PostgreSQL 的历史、特性和基本概念。
  • Getting Started:提供安装、配置和基本使用的指南。
  • Architecture:详细介绍 PostgreSQL 的架构和各个组件的功能和作用。

命令行工具和图形化工具

PostgreSQL 提供了多个工具来管理和操作数据库,最常用的包括 psql 命令行工具和 pgAdmin 图形化管理工具。以下是详细介绍:

1. psql 命令行工具

psql 是 PostgreSQL 自带的交互式命令行工具,可以用来执行 SQL 命令、脚本和数据库管理任务。

1.1 安装 psql

psql 通常随 PostgreSQL 一起安装。如果单独安装,可以使用以下命令(以 Ubuntu 为例):

sudo apt install postgresql-client

1.2 连接到数据库

使用 psql 连接到 PostgreSQL 数据库:

psql -h your_server_ip -U your_username -d your_database

  • -h:指定数据库服务器的地址。
  • -U:指定用户名。
  • -d:指定要连接的数据库名。

例如:

psql -h localhost -U myuser -d mydb

1.3 基本命令
  • 显示当前数据库中的表

    \dt

  • 描述表结构

    \d table_name

  • 退出 psql

    \q

  • 执行 SQL 查询

    SELECT * FROM table_name;

  • 运行 SQL 脚本

    \i path_to_script.sql

  • 查看连接信息

    \conninfo

1.4 常用快捷键
  • 自动补全:按 Tab 键。
  • 历史记录:使用上下箭头键浏览之前的命令。
  • 清屏:按 Ctrl + L

2. pgAdmin 图形化管理工具

pgAdmin 是 PostgreSQL 官方提供的图形化管理工具,适用于不喜欢命令行或需要可视化操作的用户。

2.1 安装 pgAdmin

pgAdmin 支持多种操作系统。以 Ubuntu 为例,使用以下命令安装:

# 添加pgAdmin存储库
curl https://www.pgadmin.org/static/packages_pgadmin_org.pub | sudo apt-key add -
sudo sh -c 'echo "deb https://ftp.postgresql.org/pub/pgadmin/pgadmin4/apt/ubuntu focal pgadmin4" > /etc/apt/sources.list.d/pgadmin4.list && apt update'# 安装桌面模式pgAdmin
sudo apt install pgadmin4-desktop

其他系统安装方法请参考 pgAdmin 官方文档.

2.2 配置和启动 pgAdmin

安装完成后,启动 pgAdmin。在 Ubuntu 上可以通过以下命令启动:

pgadmin4

初次启动时会提示设置初始管理员账号。完成后,pgAdmin 界面将在浏览器中打开。

2.3 连接到 PostgreSQL 服务器
  1. 打开 pgAdmin 后,右键点击 "Servers",选择 "Create" -> "Server..."。
  2. 在 "General" 选项卡中,为服务器连接取一个名字。
  3. 在 "Connection" 选项卡中,填写连接信息:
    • Host:服务器地址(如 localhostyour_server_ip)。
    • Port:默认端口 5432
    • Username:数据库用户名。
    • Password:数据库用户的密码。
2.4 基本操作
  • 浏览数据库:连接服务器后,可以在左侧面板中浏览数据库、表、视图、函数等。
  • 执行查询:点击工具栏上的 "Query Tool",在打开的查询编辑器中编写并执行 SQL 查询。
  • 创建和管理数据库对象:通过右键菜单可以创建新的数据库、表、视图、函数等。
  • 备份和恢复:在对象上右键点击选择 "Backup" 或 "Restore" 进行备份和恢复操作。

总结

  • psql 命令行工具:适用于习惯命令行操作的用户,功能强大且灵活,适合快速执行命令和脚本。
  • pgAdmin 图形化管理工具:适用于需要可视化操作的用户,提供了直观的界面和丰富的管理功能,适合复杂数据库管理任务。

熟练使用这两种工具,可以帮助你更高效地管理和操作 PostgreSQL 数据库。

数据定义语言 (DDL)

数据定义语言 (DDL) 是 SQL 的一部分,用于定义和管理数据库结构和对象。以下是 PostgreSQL 中常用的 DDL 语句:CREATE、ALTER 和 DROP 的详细讲解。

1. CREATE 语句

CREATE 语句用于创建数据库、表、索引和其他数据库对象。

创建数据库

创建一个新的数据库:

CREATE DATABASE dbname;

示例:

CREATE DATABASE mydb;

创建表

创建一个新的表,定义列和数据类型:

CREATE TABLE tablename ( column1 datatype1 [constraints], column2 datatype2 [constraints], ... );

示例:

CREATE TABLE users ( id SERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL, email VARCHAR(100) UNIQUE NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );

创建索引

创建一个新的索引以加速查询:

CREATE INDEX indexname ON tablename (columnname);

示例:

CREATE INDEX idx_users_email ON users (email);

2. ALTER 语句

ALTER 语句用于修改现有的数据库对象,如表和列。

修改表

添加列:

ALTER TABLE tablename ADD columnname datatype [constraints];

示例:

ALTER TABLE users ADD age INTEGER;

修改列的数据类型:

ALTER TABLE tablename ALTER COLUMN columnname TYPE newdatatype;

示例:

ALTER TABLE users ALTER COLUMN age TYPE SMALLINT;

重命名列:

ALTER TABLE tablename RENAME COLUMN oldname TO newname;

示例:

ALTER TABLE users RENAME COLUMN age TO user_age;

删除列:

ALTER TABLE tablename DROP COLUMN columnname;

示例:

ALTER TABLE users DROP COLUMN user_age;

3. DROP 语句

DROP 语句用于删除数据库对象,如数据库、表和索引。

删除数据库

删除一个数据库:

DROP DATABASE dbname;

示例:

DROP DATABASE mydb;

删除表

删除一个表及其所有数据:

DROP TABLE tablename;

示例:

DROP TABLE users;

删除索引

删除一个索引:

DROP INDEX indexname;

示例:

DROP INDEX idx_users_email;

总结

以下是 PostgreSQL 中常用的 DDL 语句的总结:

  1. CREATE 语句:用于创建数据库、表、索引等对象。

    • 创建数据库:CREATE DATABASE dbname;
    • 创建表:CREATE TABLE tablename (...);
    • 创建索引:CREATE INDEX indexname ON tablename (columnname);
  2. ALTER 语句:用于修改现有的数据库对象。

    • 添加列:ALTER TABLE tablename ADD columnname datatype;
    • 修改列的数据类型:ALTER TABLE tablename ALTER COLUMN columnname TYPE newdatatype;
    • 重命名列:ALTER TABLE tablename RENAME COLUMN oldname TO newname;
    • 删除列:ALTER TABLE tablename DROP COLUMN columnname;
  3. DROP 语句:用于删除数据库对象。

    • 删除数据库:DROP DATABASE dbname;
    • 删除表:DROP TABLE tablename;
    • 删除索引:DROP INDEX indexname;

掌握这些 DDL 语句,可以帮助你有效地管理和操作 PostgreSQL 数据库对象。

子查询和连接

在 SQL 中,子查询和连接(JOIN)是构建复杂查询的关键技术。它们用于在多个表之间进行数据检索和操作。以下是子查询和连接的详细讲解。

1. 子查询(Subquery)

子查询是在另一个查询中嵌套的查询。子查询可以用于选择、插入、更新或删除语句中,通常用于实现复杂的筛选条件。

基本语法
SELECT column1, column2, ...
FROM table1
WHERE column_name OPERATOR (SELECT column_name FROM table2 WHERE condition);

示例
  1. 查询工资高于所有员工平均工资的员工:
SELECT name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);

  1. 使用子查询获取特定部门的员工:
 
SELECT name
FROM employees
WHERE department_id = (SELECT id FROM departments WHERE name = 'Sales');

2. 连接(JOIN)

连接用于从多个表中检索数据,根据表之间的关系进行合并。常见的连接类型包括 INNER JOIN、LEFT JOIN、RIGHT JOIN 等。

INNER JOIN

INNER JOIN 返回两个表中匹配的记录。

基本语法
 
SELECT columns
FROM table1
INNER JOIN table2 ON table1.common_column = table2.common_column;

示例

查询员工及其所在部门的名称:

 
SELECT employees.name, departments.name
FROM employees
INNER JOIN departments ON employees.department_id = departments.id;

LEFT JOIN

LEFT JOIN 返回左表中的所有记录,即使右表中没有匹配的记录。未匹配的右表记录将包含 NULL 值。

基本语法
 
SELECT columns
FROM table1
LEFT JOIN table2 ON table1.common_column = table2.common_column;

示例

查询所有员工及其所在部门(包括没有部门的员工):

 
SELECT employees.name, departments.name
FROM employees
LEFT JOIN departments ON employees.department_id = departments.id;

RIGHT JOIN

RIGHT JOIN 返回右表中的所有记录,即使左表中没有匹配的记录。未匹配的左表记录将包含 NULL 值。

基本语法
 
SELECT columns
FROM table1
RIGHT JOIN table2 ON table1.common_column = table2.common_column;

示例

查询所有部门及其员工(包括没有员工的部门):

 
SELECT employees.name, departments.name
FROM employees
RIGHT JOIN departments ON employees.department_id = departments.id;

FULL JOIN

FULL JOIN 返回左右表中的所有记录,未匹配的记录包含 NULL 值。

基本语法
 
SELECT columns
FROM table1
FULL JOIN table2 ON table1.common_column = table2.common_column;

示例

查询所有员工及其所在部门,包括没有部门的员工和没有员工的部门:

 
SELECT employees.name, departments.name
FROM employees
FULL JOIN departments ON employees.department_id = departments.id;

3. 组合使用子查询和连接

在实际应用中,可以组合使用子查询和连接来完成复杂查询。

示例

查询所有员工及其所在部门的名称和工资高于平均工资的部门:

 
SELECT employees.name, departments.name, employees.salary
FROM employees
INNER JOIN departments ON employees.department_id = departments.id
WHERE employees.department_id IN (SELECT idFROM departmentsWHERE budget > (SELECT AVG(budget) FROM departments)
);

总结

  1. 子查询:在另一个查询中嵌套的查询,用于复杂的筛选条件。

    • 示例:查询工资高于平均工资的员工。
  2. 连接(JOIN):用于在多个表之间进行数据检索和操作。

    • INNER JOIN:返回两个表中匹配的记录。
    • LEFT JOIN:返回左表中的所有记录,右表中没有匹配的记录包含 NULL。
    • RIGHT JOIN:返回右表中的所有记录,左表中没有匹配的记录包含 NULL。
    • FULL JOIN:返回左右表中的所有记录,未匹配的记录包含 NULL。
  3. 组合使用:子查询和连接可以组合使用,以完成复杂的数据查询需求。

掌握子查询和连接,能够让你在 SQL 查询中处理更复杂的数据操作和分析任务。

窗口函数

窗口函数(Window Functions)是 PostgreSQL 中的一种强大功能,允许你在查询结果中对某些行进行复杂计算,而不需要聚合这些行。窗口函数通常用于分析和统计任务,如计算移动平均值、排名和累积和等。与普通聚合函数不同,窗口函数不合并多行,而是保留行的细节,同时提供额外的计算结果。

窗口函数的基本语法

窗口函数的基本语法如下:

 
window_function() OVER ([PARTITION BY partition_expression][ORDER BY sort_expression][frame_clause]
)

  • window_function():窗口函数,如 ROW_NUMBER()RANK()SUM() 等。
  • PARTITION BY:按指定的表达式将数据分区。
  • ORDER BY:按指定的表达式对数据进行排序。
  • frame_clause:指定窗口帧,可以是 ROWSRANGE,定义窗口的范围。

常见的窗口函数

1. ROW_NUMBER()

ROW_NUMBER() 返回当前行的行号,在分区中唯一。

示例

为每个部门的员工编号:

 
SELECTname,department,ROW_NUMBER() OVER (PARTITION BY department ORDER BY name) AS row_num
FROMemployees;

2. RANK() 和 DENSE_RANK()

RANK()DENSE_RANK() 用于排名。不同的是,RANK() 会在排名有重复时跳过排名序号,而 DENSE_RANK() 不会。

示例

为每个部门的员工按工资排名:

 
SELECTname,department,salary,RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS rank,DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dense_rank
FROMemployees;

3. SUM()

SUM() 计算分区内的累积和。

示例

计算每个部门中员工工资的累积和:

 
SELECTname,department,salary,SUM(salary) OVER (PARTITION BY department ORDER BY salary) AS cumulative_salary
FROMemployees;

4. AVG()

AVG() 计算分区内的平均值。

示例

计算每个部门中员工工资的平均值(包括每行的部门平均值):

 
SELECTname,department,salary,AVG(salary) OVER (PARTITION BY department) AS avg_salary
FROMemployees;

5. LAG() 和 LEAD()

LAG()LEAD() 用于访问分区中当前行的前一行或后一行的数据。

示例

获取每个员工的前一位员工的工资:

 
SELECTname,department,salary,LAG(salary, 1) OVER (PARTITION BY department ORDER BY salary) AS prev_salary
FROMemployees;

6. NTILE()

NTILE() 将分区的数据划分为指定数量的桶,并返回当前行所在的桶号。

示例

将每个部门的员工按工资划分为四个桶:

 
SELECTname,department,salary,NTILE(4) OVER (PARTITION BY department ORDER BY salary) AS bucket
FROMemployees;

窗口帧 (Frame Clause)

窗口帧用于定义窗口函数应用的行范围。可以使用 ROWSRANGE 关键字。

  • ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW:从分区开始到当前行。
  • RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING:从前一行到后一行。
示例

计算当前行及之前所有行的累积和:

 
SELECTname,department,salary,SUM(salary) OVER (PARTITION BY department ORDER BY salary ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS cumulative_salary
FROMemployees;

总结

窗口函数在 PostgreSQL 中提供了强大的分析和统计功能,可以在不丢失行细节的情况下进行复杂计算。常见的窗口函数包括 ROW_NUMBER()RANK()SUM()AVG()LAG()LEAD() 等。通过使用 PARTITION BYORDER BY 和窗口帧,可以灵活地定义窗口函数的应用范围,从而实现丰富的数据分析需求。

掌握这些窗口函数及其应用,可以大大提升你在数据处理和分析任务中的效率和能力。

视图和存储过程

视图(View)

视图是一个虚拟表,它基于 SQL 查询的结果集创建。视图不存储数据本身,而是存储查询逻辑,通过查询视图可以动态生成数据。视图用于简化复杂查询、提高安全性和重用 SQL 逻辑。

创建视图

使用 CREATE VIEW 语句创建视图:

 
CREATE VIEW view_name AS
SELECT column1, column2, ...
FROM table_name
WHERE condition;

示例

创建一个包含所有员工名字和部门名称的视图:

 
CREATE VIEW employee_departments AS
SELECT employees.name AS employee_name, departments.name AS department_name
FROM employees
JOIN departments ON employees.department_id = departments.id;

使用视图

使用视图和使用表一样:

SELECT * FROM employee_departments;

修改视图

使用 CREATE OR REPLACE VIEW 修改现有视图:

 
CREATE OR REPLACE VIEW view_name AS
SELECT column1, column2, ...
FROM table_name
WHERE condition;

示例

修改 employee_departments 视图,添加员工工资信息:

 
CREATE OR REPLACE VIEW employee_departments AS
SELECT employees.name AS employee_name, departments.name AS department_name, employees.salary
FROM employees
JOIN departments ON employees.department_id = departments.id;

删除视图

使用 DROP VIEW 删除视图:

DROP VIEW view_name;

示例

删除 employee_departments 视图:

DROP VIEW employee_departments;

存储过程(Stored Procedure)

存储过程是一组预编译的 SQL 语句,存储在数据库中,可以通过调用执行。存储过程用于封装逻辑、提高性能和安全性。

创建存储过程

使用 CREATE PROCEDURE 创建存储过程:

 
CREATE PROCEDURE procedure_name (parameters)
LANGUAGE plpgsql
AS $$
BEGIN-- SQL statements
END;
$$;

示例

创建一个简单的存储过程,插入新员工记录:

 
CREATE PROCEDURE add_employee(name VARCHAR, department_id INT, salary NUMERIC)
LANGUAGE plpgsql
AS $$
BEGININSERT INTO employees (name, department_id, salary)VALUES (name, department_id, salary);
END;
$$;

调用存储过程

使用 CALL 语句调用存储过程:

CALL procedure_name(parameters);

示例

调用 add_employee 存储过程:

CALL add_employee('Alice', 1, 50000);

修改存储过程

使用 CREATE OR REPLACE PROCEDURE 修改现有存储过程:

 
CREATE OR REPLACE PROCEDURE procedure_name (parameters)
LANGUAGE plpgsql
AS $$
BEGIN-- SQL statements
END;
$$;

示例

修改 add_employee 存储过程,增加插入记录后的通知:

CREATE OR REPLACE PROCEDURE add_employee(name VARCHAR, department_id INT, salary NUMERIC)
LANGUAGE plpgsql
AS $$
BEGININSERT INTO employees (name, department_id, salary)VALUES (name, department_id, salary);RAISE NOTICE 'Employee % added to department %', name, department_id;
END;
$$;
删除存储过程

使用 DROP PROCEDURE 删除存储过程:

DROP PROCEDURE procedure_name;

示例

删除 add_employee 存储过程:

DROP PROCEDURE add_employee;

视图和存储过程的用途

视图的用途
  1. 简化复杂查询:视图可以封装复杂的 SQL 查询,用户可以通过简单的查询访问复杂的数据集。
  2. 提高安全性:通过视图可以限制用户访问特定的数据列或行,而无需直接访问基础表。
  3. 数据重用:视图可以重用 SQL 逻辑,减少重复代码,便于维护。
  4. 数据抽象:视图可以提供数据的逻辑表示,隐藏基础表的结构和变化。
存储过程的用途
  1. 封装逻辑:存储过程可以封装复杂的业务逻辑,确保逻辑集中和一致。
  2. 提高性能:存储过程预编译并存储在数据库中,减少 SQL 解析和执行的开销。
  3. 参数化查询:存储过程可以接收参数,根据不同的输入执行不同的操作,提高灵活性。
  4. 安全性:通过存储过程可以限制直接访问表的数据,控制用户可以执行的操作,提高安全性。
  5. 事务控制:存储过程可以包含事务逻辑,确保多个操作要么全部成功,要么全部回滚。

总结

  • 视图:用于简化复杂查询、提高安全性、重用 SQL 逻辑和提供数据抽象。通过 CREATE VIEWALTER VIEWDROP VIEW 语句创建、修改和删除视图。
  • 存储过程:用于封装逻辑、提高性能、参数化查询、增强安全性和控制事务。通过 CREATE PROCEDUREALTER PROCEDUREDROP PROCEDURE 语句创建、修改和删除存储过程。

掌握视图和存储过程,可以帮助你更高效地管理和操作数据库,实现复杂的业务逻辑和数据处理需求。

索引

在 PostgreSQL 中,索引是提高查询性能的重要工具。不同类型的索引适用于不同的查询场景。以下是几种常见的索引类型及其使用场景:

1. B树索引(B-Tree Index)

B树索引是最常用的索引类型,适用于大多数查询操作。B树索引适合用于范围查询、排序和唯一性约束。

特点
  • 适用于等值查询和范围查询(如 =, <, >, <=, >=, BETWEEN)。
  • 维护数据的有序性,有助于排序操作。
  • 支持唯一性约束。
创建 B树索引

CREATE INDEX index_name ON table_name (column_name);

示例

employees 表的 name 列创建 B树索引:

CREATE INDEX idx_employees_name ON employees (name);

使用场景
  • 查找特定值或范围的值,如:

     
    SELECT * FROM employees WHERE name = 'Alice';
    SELECT * FROM employees WHERE salary BETWEEN 40000 AND 60000;
    

2. 哈希索引(Hash Index)

哈希索引适用于等值查询,但不支持范围查询。哈希索引可以在某些特定场景下提供比 B树索引更快的查找速度。

特点
  • 仅适用于等值查询(如 =)。
  • 不支持范围查询和排序。
  • 哈希索引在某些特定场景下性能优于 B树索引。
创建哈希索引

CREATE INDEX index_name ON table_name USING hash (column_name);

示例

employees 表的 email 列创建哈希索引:

CREATE INDEX idx_employees_email ON employees USING hash (email);

使用场景
  • 查找特定值,如:

    SELECT * FROM employees WHERE email = 'alice@example.com';

3. GIN 索引(Generalized Inverted Index)

GIN 索引适用于包含多个值的列,如数组、JSONB 字段和全文搜索。它在处理包含多个元素的字段时非常高效。

特点
  • 适用于包含多个值的列,如数组、JSONB 字段。
  • 提供高效的包含查询(如 @>)。
  • 支持全文搜索。
创建 GIN 索引

CREATE INDEX index_name ON table_name USING gin (column_name);

示例

documents 表的 content 列(JSONB 类型)创建 GIN 索引:

CREATE INDEX idx_documents_content ON documents USING gin (content);

使用场景
  • 查询包含特定元素的数组或 JSONB 字段,如:

    SELECT * FROM documents WHERE content @> '{"key": "value"}';

  • 全文搜索:

     
    CREATE INDEX idx_documents_content_tsv ON documents USING gin (to_tsvector('english', content));
    SELECT * FROM documents WHERE to_tsvector('english', content) @@ to_tsquery('search_term');
    

4. GiST 索引(Generalized Search Tree)

GiST 索引是一种通用索引结构,适用于多种数据类型和操作符。它特别适用于地理空间数据(PostGIS)、全文搜索和模糊匹配。

特点
  • 支持多种数据类型和操作符。
  • 适用于地理空间数据、全文搜索和模糊匹配。
  • 灵活但复杂,适用于特定场景。
创建 GiST 索引

CREATE INDEX index_name ON table_name USING gist (column_name);

示例

locations 表的 geom 列(几何类型)创建 GiST 索引:

CREATE INDEX idx_locations_geom ON locations USING gist (geom);

使用场景
  • 地理空间数据查询:

     
    SELECT * FROM locations WHERE ST_DWithin(geom, ST_GeomFromText('POINT(1 1)'), 10);
    

  • 模糊匹配:

     
    CREATE EXTENSION btree_gist;
    CREATE INDEX idx_employees_name_gist ON employees USING gist (name gist_trgm_ops);
    SELECT * FROM employees WHERE name % 'Alice';
    

总结

  • B树索引:最常用的索引类型,适用于等值查询和范围查询,支持排序和唯一性约束。
  • 哈希索引:适用于等值查询,查询速度快,但不支持范围查询和排序。
  • GIN 索引:适用于包含多个值的列,如数组和 JSONB 字段,特别高效于包含查询和全文搜索。
  • GiST 索引:通用索引结构,支持多种数据类型和操作符,适用于地理空间数据、全文搜索和模糊匹配。

根据数据和查询的特点选择合适的索引类型,可以显著提高查询性能。

使用EXPLAIN命令来分析和优化查询

查询优化是数据库性能调优的重要部分。PostgreSQL 提供了 EXPLAIN 命令,用于分析 SQL 查询的执行计划。通过查看执行计划,可以了解查询的执行步骤,并识别可能的性能瓶颈。以下是 EXPLAIN 命令及其在查询优化中的应用。

1. EXPLAIN 命令

EXPLAIN 命令显示 PostgreSQL 如何执行查询,包括表的扫描方式、连接顺序、索引使用情况等。

基本语法

EXPLAIN [ANALYZE] [VERBOSE] query;

  • ANALYZE:执行查询并显示实际运行时间和行数(非常有用)。
  • VERBOSE:显示更多详细信息。
示例

基本 EXPLAIN 示例:

EXPLAIN SELECT * FROM employees WHERE department_id = 1;

使用 ANALYZE 选项:

EXPLAIN ANALYZE SELECT * FROM employees WHERE department_id = 1;

2. 执行计划解释

执行计划由多个节点组成,每个节点表示查询的一个操作步骤。常见节点类型包括顺序扫描(Seq Scan)、索引扫描(Index Scan)、连接(Join)等。

示例解释

EXPLAIN ANALYZE SELECT * FROM employees WHERE department_id = 1;

输出示例:

 
Seq Scan on employees  (cost=0.00..35.50 rows=3 width=37) (actual time=0.026..0.029 rows=3 loops=1)Filter: (department_id = 1)Rows Removed by Filter: 50
Planning Time: 0.124 ms
Execution Time: 0.063 ms

  • Seq Scan:顺序扫描,表示全表扫描。
  • cost=0.00..35.50:估计执行成本,0.00 是启动成本,35.50 是总成本。
  • rows=3:估计返回的行数。
  • width=37:每行的宽度(字节)。
  • actual time=0.026..0.029:实际执行时间,单位是毫秒。
  • rows=3:实际返回的行数。
  • loops=1:执行次数。
优化建议
  1. 使用索引:避免顺序扫描,创建合适的索引可以显著提高查询性能。

    创建索引:

    CREATE INDEX idx_employees_department_id ON employees(department_id);

    再次执行查询并使用 EXPLAIN 查看执行计划:

    EXPLAIN ANALYZE SELECT * FROM employees WHERE department_id = 1;
    

    输出示例:

     
    Index Scan using idx_employees_department_id on employees  (cost=0.15..8.20 rows=3 width=37) (actual time=0.013..0.015 rows=3 loops=1)Index Cond: (department_id = 1)
    Planning Time: 0.157 ms
    Execution Time: 0.046 ms
    

    可以看到使用了索引扫描(Index Scan),成本和时间显著降低。

  2. 分析和维护统计信息:确保统计信息是最新的,以帮助查询优化器做出正确的决策。

    更新统计信息:

    ANALYZE employees;

  3. 优化连接顺序:合理安排连接顺序和条件,减少数据处理量。

    示例:

    EXPLAIN ANALYZE SELECT e.name, d.name
    FROM employees e
    JOIN departments d ON e.department_id = d.id
    WHERE d.name = 'Sales';
    

    输出示例:

     
    Nested Loop  (cost=0.29..12.31 rows=1 width=64) (actual time=0.030..0.032 rows=1 loops=1)->  Index Scan using idx_departments_name on departments d  (cost=0.15..8.17 rows=1 width=32) (actual time=0.018..0.019 rows=1 loops=1)Index Cond: (name = 'Sales'::text)->  Index Scan using idx_employees_department_id on employees e  (cost=0.15..4.13 rows=1 width=32) (actual time=0.009..0.010 rows=1 loops=1)Index Cond: (department_id = d.id)
    Planning Time: 0.242 ms
    Execution Time: 0.070 ms
    

    在这个示例中,Nested Loop 表示嵌套循环连接,使用了索引扫描以提高效率。

3. EXPLAIN 扩展功能

EXPLAIN BUFFERS

显示缓冲区(缓存)使用情况:

 
EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM employees WHERE department_id = 1;

输出示例:

 
Index Scan using idx_employees_department_id on employees  (cost=0.15..8.20 rows=3 width=37) (actual time=0.013..0.015 rows=3 loops=1)Index Cond: (department_id = 1)Buffers: shared hit=3
Planning Time: 0.157 ms
Execution Time: 0.046 ms

EXPLAIN (FORMAT JSON)

以 JSON 格式输出执行计划,便于程序处理:

EXPLAIN (FORMAT JSON) SELECT * FROM employees WHERE department_id = 1;

总结

  1. 使用 EXPLAINEXPLAIN ANALYZE:了解查询的执行计划和实际执行时间。
  2. 创建合适的索引:通过创建索引提高查询性能。
  3. 更新统计信息:确保统计信息是最新的,以帮助优化器做出正确决策。
  4. 合理安排连接顺序:优化连接顺序和条件,减少数据处理量。
  5. 使用扩展功能:如 EXPLAIN BUFFERSEXPLAIN (FORMAT JSON) 获取更多详细信息。

通过 EXPLAIN 命令分析查询执行计划,可以识别并解决性能瓶颈,从而优化 PostgreSQL 查询性能。

性能调优:了解PostgreSQL的性能优化技巧和配置参数

性能调优是确保 PostgreSQL 数据库在高负载下高效运行的重要工作。以下是一些常见的 PostgreSQL 性能优化技巧和配置参数的详细讲解。

1. 配置参数优化

PostgreSQL 配置文件通常位于 postgresql.conf 中。以下是一些重要的配置参数及其优化建议。

1.1 shared_buffers

shared_buffers 决定 PostgreSQL 可以用来缓存数据的内存大小。通常设置为总内存的 25%。

shared_buffers = 1GB
1.2 work_mem

work_mem 决定每个查询操作(如排序和哈希表操作)可以使用的内存大小。增大 work_mem 可以提高复杂查询的性能,但需要考虑并发查询的数量。

 
work_mem = 64MB

1.3 maintenance_work_mem

maintenance_work_mem 用于维护操作(如 VACUUMCREATE INDEXALTER TABLE 等),可以设置较大以加快这些操作的速度。

 
maintenance_work_mem = 256MB

1.4 effective_cache_size

effective_cache_size 告诉 PostgreSQL 操作系统缓存的大小,以帮助查询优化器做出更好的决策。通常设置为总内存的 50% 到 75%。

 
effective_cache_size = 4GB

1.5 checkpoint_segmentscheckpoint_completion_target

这些参数控制 WAL(Write-Ahead Logging)日志的检查点频率。增大 checkpoint_segmentscheckpoint_completion_target 可以减少检查点的频率,从而提高性能。

 
checkpoint_segments = 32
checkpoint_completion_target = 0.9

1.6 wal_buffers

wal_buffers 决定用于 WAL 日志缓存的内存大小。对于大多数系统,增大 wal_buffers 可以提高写性能。

 
wal_buffers = 16MB

2. 查询优化技巧

2.1 使用索引

创建适当的索引可以大大提高查询性能。常见的索引类型包括 B 树索引、哈希索引、GIN 索引和 GiST 索引。

 
CREATE INDEX idx_users_email ON users (email);
2.2 使用 EXPLAIN 分析查询

使用 EXPLAIN 命令查看查询的执行计划,识别可能的性能瓶颈。

 
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'alice@example.com';

2.3 避免全表扫描

通过优化查询条件和创建索引,尽量避免全表扫描。

2.4 使用连接池

使用连接池可以减少数据库连接的开销,提高并发查询性能。

3. 数据库维护

3.1 定期 VACUUMANALYZE

定期执行 VACUUMANALYZE 可以清理无用数据,更新统计信息,帮助优化查询性能。

VACUUM ANALYZE;
3.2 自动化维护任务

设置 autovacuum 参数,自动执行 VACUUMANALYZE 任务。

 
autovacuum = on
autovacuum_naptime = 1min
autovacuum_vacuum_threshold = 50
autovacuum_analyze_threshold = 50

4. 硬件和系统优化

4.1 磁盘 I/O 优化

使用 SSD 可以显著提高数据库的 I/O 性能。确保文件系统支持和优化大 I/O 操作。

4.2 内存优化

增加服务器内存可以提高缓存和查询性能。确保 PostgreSQL 的配置参数充分利用系统内存。

4.3 CPU 优化

更多和更快的 CPU 核心可以提高并发查询的处理能力。

5. 高级优化技巧

5.1 分区表

对于大表,可以使用分区表来提高查询性能和管理效率。

 
CREATE TABLE sales (id serial PRIMARY KEY,sale_date date NOT NULL,amount numeric
) PARTITION BY RANGE (sale_date);CREATE TABLE sales_2023 PARTITION OF sales FOR VALUES FROM ('2023-01-01') TO ('2024-01-01');

5.2 并行查询

PostgreSQL 支持并行查询,可以显著提高大数据集上的查询性能。

 
max_parallel_workers_per_gather = 4

总结

  • 配置参数优化:调整 shared_bufferswork_memeffective_cache_size 等参数,提高整体性能。
  • 查询优化:使用索引、EXPLAIN 分析查询、避免全表扫描、使用连接池等技巧。
  • 数据库维护:定期执行 VACUUMANALYZE、启用自动维护任务。
  • 硬件和系统优化:优化磁盘 I/O、增加内存、使用更多 CPU 核心。
  • 高级优化技巧:使用分区表和并行查询来处理大数据集。

通过综合运用这些优化技巧和配置参数,可以显著提高 PostgreSQL 数据库的性能和响应速度。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/14525.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构(Java实现):ArrayList

目录 1.ArrayList简介2.ArrayList构造方法分析3.ArrayList的add方法以及扩容机制4.ArrayList常用方法5.ArrayList遍历6.ArrayList的缺陷 1.ArrayList简介 在集合框架中&#xff0c;ArrayList是一个普通的类&#xff0c;实现了List接口&#xff0c;具体框架图如下&#xff1a; …

编写一个llvm编译器插件,完成在store汇编指令前对内存合法性的check。

dds(iceoryx、fastdds等)中间件采用了共享内存&#xff0c;如果app内存越界将共享内存踩踏坏了&#xff0c;将会形成灾难。本插件可以检测到app是否在写共享内存&#xff0c;如果是&#xff0c;我们可以让app assert。从而提高dds的稳定性 插件效果&#xff1a; 插件源码&…

话题:如何让大模型变得更聪明?

随着人工智能&#xff08;AI&#xff09;技术的迅速发展&#xff0c;大模型&#xff08;如GPT-4、BERT、Transformer等&#xff09;在自然语言处理、图像识别和语音识别等领域取得了显著成果。然而&#xff0c;如何让大模型变得更聪明&#xff0c;进一步提升其性能和应用效果&a…

Netty: Netty中的组件

文章目录 一、EventLoop1、EventLoop2、EventLoopGroup&#xff08;1&#xff09;处理普通时间和定时任务&#xff08;2&#xff09;处理IO任务 二、Channel三、Future&Promise四、Handler&Pipeline五、ByteBuf 一、EventLoop 1、EventLoop EventLoop本质是一个单线程…

Jetbrain | IDEA的启动logo替换成可爱的vtuber-logo

看了这个&#xff0c;好可爱 【上Github热榜了&#xff01;当编程语言的Logo变得可爱起来~】 又看了这个 光速整活&#xff0c;强啊 看到很多人整IDEA的logo包括我自己&#xff0c;都不是特别方便的搞&#xff0c;我就直接把文件放在绑定资源里直接下吧 然后直接找到本体的安…

ios swift5 codable字典转模型,第三方库SmartCodable

文章目录 1.用第三方库SmartCodable, github地址2.使用示例 1.用第三方库SmartCodable, github地址 SmartCodable - github 2.使用示例 import Foundation import SmartCodablestruct CommonModel: SmartCodable {var message: String ""var success: Bool fals…

【深度学习】与【PyTorch实战】

目录 一、深度学习基础 1.1 神经网络简介 1.2 激活函数 1.3 损失函数 1.4 优化算法 二、PyTorch基础 2.1 PyTorch简介 2.2 张量操作 2.3 构建神经网络 2.4训练模型 2.5 模型评估 三、PyTorch实战 3.1 数据加载与预处理 3.2 模型定义与训练 3.3 模型评估与调优 3…

成都青年AI人才崭露头角,知了汇智科技助力孵化营大放异彩

5月18日-19日&#xff0c;为期两天的成都国际商贸城青年&#xff08;大学生&#xff09;AI应用孵化营活动在热烈的氛围中圆满落幕。本次活动由成都国际商贸城、成都成商数字科技有限公司、成都知了汇智科技有限公司及成都电商职教集团联合举办&#xff0c;旨在为青年&#xff0…

丢失api-ms-win-crt-runtime-l1-1-0.dll的多种解决方法分析,教你简单的一键修复

在使用Windows操作系统时&#xff0c;用户可能会遇到一个涉及丢失 ​api-ms-win-crt-runtime-l1-1-0.dll文件的警告&#xff0c;这可能导致某些程序无法正常运行。该DLL文件属于Microsoft Visual C Redistributable软件包的一部分&#xff0c;这个软件包为多个应用提供运行时支…

Mybatis-plus的两种分页方案

Mybatis-plus的两种分页方案 底层的逻辑是写出最终执行的sql或者selectPage方法等&#xff0c;中间需要配置相应的page拦截器。 注意&#xff1a;如没有配置拦截器&#xff0c;直接执行就会存在total的值为0&#xff0c;此方法无效。 1. 基于MP的IPage接口实现 使用步骤&am…

深度学习-Softmax回归+损失函数+图像分类数据集

目录 Softmax回归回归 VS 分类Kaggle上的分类问题 从回归到多类分类回归分类从回归到多类分类-均方损失从回归到多类分类-无校验比例从回归到多类分类-校验比例 Softmax和交叉熵损失总结损失函数均方损失绝对值损失函数鲁棒损失 图像分类数据集通过框架中内置函数将FashionMNIS…

RabbitMQ---交换机-Fanout-Direct

Publisher&#xff1a;生产者&#xff0c;不再发送消息到队列中&#xff0c;而是发给交换机Exchange&#xff1a;交换机&#xff0c;一方面&#xff0c;接收生产者发送的消息。另一方面&#xff0c;知道如何处理消息&#xff0c;例如递交给某个特别队列、递交给所有队列、或是将…

删除实例分割中的特定标签

用labelme软件对图像进行实例分割或语义分割标注后会得到json文件&#xff0c;如果想要删除某个特定标签&#xff0c;可以使用如下代码&#xff0c;完整代码下载地址&#xff1a;代码地址 import json import os# 要处理的json文件夹路径 folder_path H:/json # 需要删除的标…

如何一键生成多个文本二维码?excel表格批量生码的方法

现在很多人会将文本信息做成二维码来展示&#xff0c;当有同类型内容生成大量二维码时&#xff0c;可以使用将文本导入excel表格的方式&#xff0c;将表格中的每条数据批量生成二维码&#xff0c;可以有效提升二维码制作的速度和效率。下面就让小编来将具体的操作步骤分享给大家…

LangChain API 2.0

转载整理自&#xff1a;https://api.python.langchain.com/en/latest/langchain_api_reference.html 文章目录 1、langchain.agentsClassesFunctions 2、langchain.callbacksClasses 3、langchain.chainsClassesFunctions 4、langchain.embeddingsClasses 5、langchain.evaluat…

二叉树顺序结构及链式结构

一.二叉树的顺序结构 1.定义&#xff1a;使用数组存储数据&#xff0c;一般使用数组只适合表示完全二叉树&#xff0c;此时不会有空间的浪费 注&#xff1a;二叉树的顺序存储在逻辑上是一颗二叉树&#xff0c;但是在物理上是一个数组&#xff0c;此时需要程序员自己想清楚调整…

http流式返回

HTTP流式返回&#xff08;Stream&#xff09;是一种服务器向客户端传输数据的方式允许数据分块发送而不是一次性发送完毕。 这样客户端可以在接收到第一部分数据时就开始处理&#xff0c;而不必等待整个响应完成。 应用场景&#xff1a; 2.1 业务场景&#xff1a;图表的监听&a…

手动安装maven依赖到本地仓库

使用mvn install命令安装jar包到指定的仓库。 命令如下&#xff1a; mvn install:install-file -Dmaven.repo.localC:\Users\liyong.m2\repository -DgroupIdcom.aspose -DartifactIdwords -Dversion18.4 -Dpackagingjar -DfileC:\Users\liyong\Desktop\jar\words-18.4.jar 解释…

grafana + Prometheus + node-exporter + pushgateway + alertmanager的监控解决方案

业内比较著名的监控解决方案&#xff0c;据笔者所知&#xff0c;大概是三套&#xff1a; 一个是zabbix的解决方案&#xff0c;一个是prometheusgrafana&#xff0c;一个是ELK zabbix比较重&#xff0c;而且原生支持监控SNMP&#xff0c;自带一个仪表盘&#xff0c;不需要额外…

docker redis 持久化

1、拉取redis镜像 docker pull redis:latest 2、 mkdir /data/redis 3、填充redis.conf文件及根据需求修改相应的配置 •通过官网地址找到对应版本的配置文件 •将配置信息复制到redis.conf中 •常见的修改配置 https://redis.io/docs/latest/operate/oss_and_stack/managem…