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.pswp.cn/diannao/14525.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/14525.shtml
英文地址,請注明出處:http://en.pswp.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…