Lệnh psql

← Biểu thức điều kiện - CASE, COALESCE, NULLIF, CAST | → Công thức thực dụng - EXPLAIN, xóa trùng, so sánh bảng

Bạn sẽ học được

Làm chủ psql — công cụ dòng lệnh chính thức. Học tốt psql giúp bạn nhanh hơn nhiều so với dùng giao diện đồ họa.


1. Kết nối

psql -U <user> -h <host> -p <port> -d <database>
 
psql -U postgres                                  # local, database mặc định
psql -U postgres -d dvdrental                     # chỉ định database
psql -h 192.168.1.50 -p 5432 -U tungdd -d app     # máy từ xa
psql "postgresql://user:pass@host:5432/db?sslmode=require"   # URI

Biến môi trường thay cho tham số:

export PGHOST=localhost
export PGUSER=postgres
export PGDATABASE=dvdrental
export PGPASSWORD=matkhau        # ⚠️ hiện trong lịch sử shell
psql                              # dùng luôn các biến trên

An toàn hơn — file ~/.pgpass (quyền chmod 600):

hostname:port:database:username:password
localhost:5432:dvdrental:postgres:matkhau
*:5432:*:tungdd:matkhau_chung

1.1. Chạy lệnh không vào shell

psql -d dvdrental -c "SELECT count(*) FROM film;"       # một lệnh
psql -d dvdrental -f script.sql                          # chạy file
psql -d dvdrental -A -t -c "SELECT count(*) FROM film;"  # chỉ giá trị, không định dạng
psql -d dvdrental --csv -c "SELECT * FROM actor LIMIT 5" # xuất CSV
CờÝ nghĩa
-cChạy một lệnh rồi thoát
-fChạy file SQL
-AKhông căn chỉnh cột
-tKhông hiện tiêu đề và số dòng
-qIm lặng (không in thông báo)
-1Chạy cả file trong một giao dịch
-v ON_ERROR_STOP=1Dừng ngay khi gặp lỗi
-XBỏ qua ~/.psqlrc
# Chạy migration an toàn: một giao dịch, dừng khi lỗi
psql -d app -1 -v ON_ERROR_STOP=1 -f migration.sql

2. Lệnh thông tin (\d)

LệnhHiển thị
\l hoặc \listDanh sách database
\c ten_dbChuyển database
\dnDanh sách schema
\dtBảng
\dt+Bảng kèm kích thước
\dvView
\dmMaterialized view
\diIndex
\dsSequence
\dfFunction
\dTKiểu dữ liệu
\duRole / user
\dp hoặc \zQuyền truy cập
\dxExtension đã cài
\dconfigTham số cấu hình
\d ten_bangCấu trúc bảng
\d+ ten_bangCấu trúc chi tiết (kèm dung lượng, mô tả)

Thêm + để chi tiết hơn, thêm S để hiện cả đối tượng hệ thống:

\dt              -- bảng của người dùng
\dtS             -- gồm cả bảng hệ thống
\dt+ *film*      -- lọc theo mẫu tên
\d film*         -- mọi đối tượng bắt đầu bằng "film"

2.1. Ví dụ \d film

                    Table "public.film"
      Column      |           Type           | Nullable |
------------------+--------------------------+----------+
 film_id          | integer                  | not null |
 title            | character varying(255)   | not null |
 description      | text                     |          |
 release_year     | year                     |          |
 language_id      | smallint                 | not null |
 rental_duration  | smallint                 | not null |
 rental_rate      | numeric(4,2)             | not null |
 ...
Indexes:
    "film_pkey" PRIMARY KEY, btree (film_id)
    "film_fulltext_idx" gist (fulltext)
    "idx_fk_language_id" btree (language_id)
    "idx_title" btree (title)
Foreign-key constraints:
    "film_language_id_fkey" FOREIGN KEY (language_id) REFERENCES language(language_id)
Referenced by:
    TABLE "film_actor" CONSTRAINT ... FOREIGN KEY (film_id) REFERENCES film(film_id)
    ...
Triggers:
    last_updated BEFORE UPDATE ON film FOR EACH ROW EXECUTE FUNCTION last_updated()

Mục Referenced by rất hữu ích — cho biết bảng nào phụ thuộc vào bảng này trước khi bạn DROP.


3. Định dạng đầu ra

LệnhTác dụng
\xBật/tắt hiển thị dọc
\x autoTự động chuyển khi bảng quá rộng
\aBật/tắt căn chỉnh cột
\tBật/tắt tiêu đề và số dòng
\pset border 2Kiểu viền (0, 1, 2)
\pset null '[NULL]'Cách hiển thị NULL
\pset format csvĐịnh dạng: aligned, csv, html, latex, wrapped
\pset pager offTắt phân trang
\pset linestyle unicodeViền bảng đẹp hơn

3.1. \x — cứu cánh cho bảng nhiều cột

\x
SELECT * FROM film WHERE film_id = 1;
-[ RECORD 1 ]----+------------------------------------------
film_id          | 1
title            | Academy Dinosaur
description      | A Epic Drama of a Feminist And a Mad ...
release_year     | 2006
language_id      | 1
rental_duration  | 6
rental_rate      | 0.99
length           | 86
replacement_cost | 20.99
rating           | PG

Dễ đọc hơn hẳn so với bảng ngang bị cắt.


4. Nhập/xuất và thực thi file

LệnhTác dụng
\i duong_dan.sqlChạy file SQL
\ir duong_dan.sqlChạy file, đường dẫn tương đối với file hiện tại
\o ten_fileGhi kết quả ra file
\oTrở về màn hình
\copy ...Nhập/xuất CSV phía client
\g ten_fileChạy lệnh cuối, ghi ra file
\w ten_fileGhi bộ đệm truy vấn ra file
\eMở trình soạn thảo để sửa truy vấn
\ef ten_hamSửa định nghĩa function
\! lenh_shellChạy lệnh shell
-- Xuất kết quả ra HTML
\pset format html
\o bao_cao.html
SELECT * FROM film LIMIT 10;
\o
\pset format aligned
 
-- Xuất CSV
\copy (SELECT * FROM film WHERE length > 150) TO 'phim.csv' CSV HEADER
 
-- Mở vim/nano để viết truy vấn dài
\e

→ Nhập và xuất dữ liệu CSV


5. Biến và tương tác

\set ten_bien 'gia_tri'
\echo :ten_bien
\unset ten_bien
\set                          -- liệt kê tất cả biến

Dùng biến trong truy vấn:

\set ma_phim 100
SELECT * FROM film WHERE film_id = :ma_phim;
 
\set ten 'Academy Dinosaur'
SELECT * FROM film WHERE title = :'ten';     -- :'x' bọc nháy đơn (giá trị)
 
\set bang 'film'
SELECT count(*) FROM :"bang";                -- :"x" bọc nháy kép (định danh)

Nhập từ bàn phím:

\prompt 'Nhập mã phim: ' ma
SELECT title FROM film WHERE film_id = :ma;

5.1. Biến hệ thống hữu ích

BiếnTác dụng
AUTOCOMMITon/off
ON_ERROR_STOPDừng script khi lỗi
ON_ERROR_ROLLBACKinteractive — savepoint ngầm
VERBOSITYdefault, verbose, terse
HISTSIZESố lệnh lưu trong lịch sử
COMP_KEYWORD_CASEupper — tự hoàn thành từ khóa viết hoa
PROMPT1Định dạng dấu nhắc

6. Lịch sử và chỉnh sửa

Phím / LệnhTác dụng
↑ / ↓Duyệt lịch sử
Ctrl+RTìm ngược trong lịch sử
TabTự động hoàn thành tên bảng/cột/từ khóa
Ctrl+A / Ctrl+EVề đầu / cuối dòng
Ctrl+UXóa từ con trỏ về đầu dòng
Ctrl+LXóa màn hình
Ctrl+CHủy câu lệnh đang gõ
\sXem lịch sử lệnh
\s file.txtLưu lịch sử ra file
\rXóa bộ đệm truy vấn
\pXem bộ đệm truy vấn hiện tại

Tab là tính năng bị đánh giá thấp nhất: gõ SELECT * FROM fi rồi Tab sẽ tự điền film.


7. Trợ giúp

\?              -- danh sách lệnh meta
\?  variables   -- trợ giúp về biến
\h              -- danh sách lệnh SQL
\h SELECT       -- cú pháp đầy đủ của SELECT
\h ALTER TABLE  -- cú pháp ALTER TABLE
\q              -- thoát

\h cực kỳ hữu ích — không cần mở trình duyệt để tra cú pháp.


8. Đo thời gian và phân tích

\timing on
SELECT count(*) FROM payment;
-- Time: 12.345 ms
 
EXPLAIN ANALYZE SELECT * FROM film WHERE title = 'Academy Dinosaur';

→ Công thức thực dụng - EXPLAIN, xóa trùng, so sánh bảng

8.1. \watch — chạy lặp lại

SELECT count(*), max(payment_date) FROM payment;
\watch 5      -- chạy lại mỗi 5 giây, Ctrl+C để dừng

Rất hữu ích khi theo dõi tiến trình nạp dữ liệu hoặc quan sát kết nối:

SELECT pid, state, wait_event, left(query, 50)
FROM pg_stat_activity WHERE state <> 'idle';
\watch 2

8.2. \gexec — chạy kết quả truy vấn như lệnh SQL

Tính năng mạnh nhất mà ít người biết:

-- Sinh và chạy lệnh ANALYZE cho mọi bảng
SELECT format('ANALYZE %I;', tablename)
FROM pg_tables WHERE schemaname = 'public'
\gexec
 
-- Xóa tất cả bảng có tiền tố tmp_
SELECT format('DROP TABLE %I CASCADE;', tablename)
FROM pg_tables WHERE tablename LIKE 'tmp_%'
\gexec
 
-- Tạo index cho mọi cột khóa ngoại còn thiếu
SELECT format('CREATE INDEX ON %I (%I);', tbl, col) FROM ...
\gexec

9. File cấu hình ~/.psqlrc

Đây là cấu hình khuyến nghị:

-- Im lặng khi khởi động
\set QUIET 1
 
-- Hiển thị
\x auto
\pset null '[NULL]'
\pset linestyle unicode
\pset border 2
 
-- Tiện ích
\timing on
\set HISTSIZE 10000
\set HISTFILE ~/.psql_history- :DBNAME
\set COMP_KEYWORD_CASE upper
\set VERBOSITY verbose
 
-- An toàn
\set ON_ERROR_ROLLBACK interactive
 
-- Dấu nhắc: user@database:schema
\set PROMPT1 '%[%033[1;32m%]%n@%/%[%033[0m%]%R%# '
 
-- Truy vấn viết tắt
\set phien 'SELECT pid, state, now()-query_start AS thoi_gian, left(query,60) FROM pg_stat_activity WHERE state <> ''idle'' ORDER BY 3 DESC;'
\set kich_thuoc 'SELECT relname, pg_size_pretty(pg_total_relation_size(c.oid)) AS kich_thuoc FROM pg_class c JOIN pg_namespace n ON n.oid=c.relnamespace WHERE n.nspname=''public'' AND c.relkind=''r'' ORDER BY pg_total_relation_size(c.oid) DESC LIMIT 20;'
\set index_thua 'SELECT schemaname, relname, indexrelname, idx_scan FROM pg_stat_user_indexes WHERE idx_scan = 0 ORDER BY relname;'
 
\set QUIET 0
\echo 'Đã nạp ~/.psqlrc — gõ :phien, :kich_thuoc, :index_thua'

Dùng:

:phien          -- xem các truy vấn đang chạy
:kich_thuoc     -- 20 bảng lớn nhất
:index_thua     -- index chưa từng được dùng

\set HISTFILE ~/.psql_history- :DBNAME

Mỗi database có file lịch sử riêng — Ctrl+R chỉ tìm trong các lệnh liên quan tới database hiện tại.


10. Truy vấn giám sát hữu ích

-- Kết nối đang hoạt động
SELECT pid, usename, application_name, state,
       now() - query_start AS thoi_gian, left(query, 60) AS truy_van
FROM pg_stat_activity
WHERE state <> 'idle' AND pid <> pg_backend_pid()
ORDER BY thoi_gian DESC;
 
-- Hủy truy vấn
SELECT pg_cancel_backend(1234);      -- nhẹ nhàng
SELECT pg_terminate_backend(1234);   -- cưỡng bức
 
-- Kích thước database
SELECT datname, pg_size_pretty(pg_database_size(datname))
FROM pg_database ORDER BY pg_database_size(datname) DESC;
 
-- Kích thước bảng và index
SELECT relname AS bang,
       pg_size_pretty(pg_total_relation_size(c.oid)) AS tong,
       pg_size_pretty(pg_relation_size(c.oid))       AS du_lieu,
       pg_size_pretty(pg_indexes_size(c.oid))        AS index
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE n.nspname = 'public' AND c.relkind = 'r'
ORDER BY pg_total_relation_size(c.oid) DESC;
 
-- Index chưa từng dùng (ứng viên để xóa)
SELECT schemaname, relname, indexrelname,
       pg_size_pretty(pg_relation_size(indexrelid)) AS kich_thuoc
FROM pg_stat_user_indexes
WHERE idx_scan = 0
ORDER BY pg_relation_size(indexrelid) DESC;
 
-- Bảng phình to (cần VACUUM)
SELECT relname, n_live_tup, n_dead_tup,
       round(100.0 * n_dead_tup / NULLIF(n_live_tup + n_dead_tup, 0), 1) AS pct_chet,
       last_autovacuum
FROM pg_stat_user_tables
WHERE n_dead_tup > 1000
ORDER BY n_dead_tup DESC;
 
-- Khóa đang chờ
SELECT blocked.pid AS bi_chan, blocking.pid AS dang_chan,
       left(blocked.query, 50) AS truy_van_bi_chan
FROM pg_stat_activity blocked
JOIN pg_stat_activity blocking
  ON blocking.pid = ANY(pg_blocking_pids(blocked.pid))
WHERE cardinality(pg_blocking_pids(blocked.pid)) > 0;

11. Bảng tra cứu nhanh

KẾT NỐI              THÔNG TIN            ĐỊNH DẠNG
\c db                \l    database       \x       dọc
\conninfo            \dt   bảng           \x auto  tự động
\q    thoát          \d t  cấu trúc       \a       căn chỉnh
                     \d+ t chi tiết       \t       tiêu đề
FILE                 \di   index          \pset null '[NULL]'
\i  file.sql         \dv   view
\o  file             \df   function       BIẾN
\copy ... TO/FROM    \du   user           \set x 'v'
\e    soạn thảo      \dx   extension      :x  :'x'  :"x"

TIỆN ÍCH             TRỢ GIÚP             LỊCH SỬ
\timing on           \?    lệnh meta      ↑ ↓  duyệt
\watch 5             \h    lệnh SQL       Ctrl+R  tìm
\gexec               \h SELECT            Tab  hoàn thành
\! lenh_shell                             \s   xem lịch sử

12. Bài tập

  1. Tạo ~/.psqlrc với \x auto, \timing on, và \pset null '[NULL]'.
  2. Dùng \d+ xem kích thước tất cả bảng trong dvdrental. Bảng nào lớn nhất?
  3. Dùng \gexec sinh lệnh ANALYZE cho mọi bảng trong schema public.
  4. Xuất kết quả truy vấn ra file HTML.
  5. Dùng \watch theo dõi số dòng của một bảng trong khi chạy INSERT ở phiên khác.
  6. Định nghĩa biến :top_phim trong .psqlrc trả về 10 phim dài nhất.
  7. Tìm các index chưa từng được dùng trong dvdrental.
  8. Chạy một file SQL trong một giao dịch duy nhất, dừng ngay khi có lỗi.

13. Tóm tắt

  • \d, \dt, \l, \du, \dx là bộ lệnh khám phá cơ bản; thêm + để chi tiết.
  • \x auto cứu bạn khỏi bảng bị cắt xén — nên bật mặc định.
  • \pset null '[NULL]' giúp phân biệt NULL với chuỗi rỗng.
  • \copy cho file trên máy bạn; COPY cho file trên máy chủ.
  • \gexec sinh và chạy SQL động — công cụ tự động hóa mạnh nhất của psql.
  • \watch n chạy lặp truy vấn — hữu ích khi giám sát.
  • \h SELECT tra cú pháp nhanh hơn mở trình duyệt.
  • psql -1 -v ON_ERROR_STOP=1 -f file.sql là cách chạy migration an toàn.
  • Đầu tư vào ~/.psqlrc một lần, hưởng lợi mãi mãi.

← Biểu thức điều kiện - CASE, COALESCE, NULLIF, CAST | → Công thức thực dụng - EXPLAIN, xóa trùng, so sánh bảng