Initial commit
This commit is contained in:
467
skills/databases/references/postgresql-psql-cli.md
Normal file
467
skills/databases/references/postgresql-psql-cli.md
Normal file
@@ -0,0 +1,467 @@
|
||||
# PostgreSQL psql CLI
|
||||
|
||||
Command-line interface for PostgreSQL: connection, meta-commands, scripting, and interactive usage.
|
||||
|
||||
## Connection
|
||||
|
||||
### Basic Connection
|
||||
```bash
|
||||
# Connect to database
|
||||
psql -U username -d database -h hostname -p 5432
|
||||
|
||||
# Connect using URI
|
||||
psql postgresql://username:password@hostname:5432/database
|
||||
|
||||
# Environment variables
|
||||
export PGUSER=postgres
|
||||
export PGPASSWORD=mypassword
|
||||
export PGHOST=localhost
|
||||
export PGPORT=5432
|
||||
export PGDATABASE=mydb
|
||||
psql
|
||||
```
|
||||
|
||||
### Password File (~/.pgpass)
|
||||
```bash
|
||||
# Format: hostname:port:database:username:password
|
||||
# chmod 600 ~/.pgpass
|
||||
localhost:5432:mydb:postgres:mypassword
|
||||
*.example.com:5432:*:appuser:apppass
|
||||
```
|
||||
|
||||
### SSL Connection
|
||||
```bash
|
||||
# Require SSL
|
||||
psql "host=hostname sslmode=require user=username dbname=database"
|
||||
|
||||
# Verify certificate
|
||||
psql "host=hostname sslmode=verify-full \
|
||||
sslcert=/path/to/client.crt \
|
||||
sslkey=/path/to/client.key \
|
||||
sslrootcert=/path/to/ca.crt"
|
||||
```
|
||||
|
||||
## Essential Meta-Commands
|
||||
|
||||
### Database Navigation
|
||||
```bash
|
||||
\l or \list # List databases
|
||||
\l+ # List with sizes
|
||||
\c database # Connect to database
|
||||
\c database username # Connect as user
|
||||
\conninfo # Connection info
|
||||
```
|
||||
|
||||
### Schema Inspection
|
||||
```bash
|
||||
\dn # List schemas
|
||||
\dt # List tables
|
||||
\dt+ # Tables with sizes
|
||||
\dt *.* # All tables, all schemas
|
||||
\di # List indexes
|
||||
\dv # List views
|
||||
\dm # List materialized views
|
||||
\ds # List sequences
|
||||
\df # List functions
|
||||
```
|
||||
|
||||
### Object Description
|
||||
```bash
|
||||
\d tablename # Describe table
|
||||
\d+ tablename # Detailed description
|
||||
\d indexname # Describe index
|
||||
\df functionname # Describe function
|
||||
\du # List users/roles
|
||||
\dp tablename # Show permissions
|
||||
```
|
||||
|
||||
### Output Formatting
|
||||
```bash
|
||||
\x # Toggle expanded output
|
||||
\x on # Enable expanded
|
||||
\x off # Disable expanded
|
||||
\a # Toggle aligned output
|
||||
\t # Toggle tuples only
|
||||
\H # HTML output
|
||||
\pset format csv # CSV format
|
||||
\pset null '[NULL]' # Show NULL values
|
||||
```
|
||||
|
||||
### Execution Commands
|
||||
```bash
|
||||
\i filename.sql # Execute SQL file
|
||||
\o output.txt # Redirect output to file
|
||||
\o # Stop redirecting
|
||||
\! command # Execute shell command
|
||||
\timing # Toggle timing
|
||||
\q # Quit
|
||||
```
|
||||
|
||||
## psql Command-Line Options
|
||||
|
||||
```bash
|
||||
# Connection
|
||||
-h hostname # Host
|
||||
-p port # Port (default 5432)
|
||||
-U username # Username
|
||||
-d database # Database
|
||||
-W # Prompt for password
|
||||
|
||||
# Execution
|
||||
-c "SQL" # Execute command and exit
|
||||
-f file.sql # Execute file
|
||||
--command="SQL" # Execute command
|
||||
|
||||
# Output
|
||||
-t # Tuples only (no headers)
|
||||
-A # Unaligned output
|
||||
-F "," # Field separator
|
||||
-o output.txt # Output to file
|
||||
-q # Quiet mode
|
||||
-x # Expanded output
|
||||
|
||||
# Script options
|
||||
-1 # Execute as transaction
|
||||
--on-error-stop # Stop on error
|
||||
-v variable=value # Set variable
|
||||
-L logfile.log # Log session
|
||||
```
|
||||
|
||||
## Running SQL
|
||||
|
||||
### Interactive Queries
|
||||
```sql
|
||||
-- Simple query
|
||||
SELECT * FROM users;
|
||||
|
||||
-- Multi-line (ends with semicolon)
|
||||
SELECT id, name, email
|
||||
FROM users
|
||||
WHERE active = true;
|
||||
|
||||
-- Edit in editor
|
||||
\e
|
||||
|
||||
-- Repeat last query
|
||||
\g
|
||||
|
||||
-- Send to file
|
||||
\g output.txt
|
||||
```
|
||||
|
||||
### Variables
|
||||
```bash
|
||||
# Set variable
|
||||
\set myvar 'value'
|
||||
\set limit 10
|
||||
|
||||
# Use variable
|
||||
SELECT * FROM users LIMIT :limit;
|
||||
|
||||
# String variable (quoted)
|
||||
\set username 'alice'
|
||||
SELECT * FROM users WHERE name = :'username';
|
||||
|
||||
# Show all variables
|
||||
\set
|
||||
|
||||
# Unset variable
|
||||
\unset myvar
|
||||
```
|
||||
|
||||
### Scripts
|
||||
```sql
|
||||
-- script.sql
|
||||
\set ON_ERROR_STOP on
|
||||
|
||||
BEGIN;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
email TEXT UNIQUE
|
||||
);
|
||||
|
||||
INSERT INTO users (name, email) VALUES
|
||||
('Alice', 'alice@example.com'),
|
||||
('Bob', 'bob@example.com');
|
||||
|
||||
COMMIT;
|
||||
|
||||
\echo 'Script completed!'
|
||||
```
|
||||
|
||||
```bash
|
||||
# Execute script
|
||||
psql -d mydb -f script.sql
|
||||
|
||||
# With error stopping
|
||||
psql -d mydb -f script.sql --on-error-stop
|
||||
|
||||
# In single transaction
|
||||
psql -d mydb -1 -f script.sql
|
||||
```
|
||||
|
||||
## Data Import/Export
|
||||
|
||||
### COPY (Server-side)
|
||||
```sql
|
||||
-- Export to CSV
|
||||
COPY users TO '/tmp/users.csv' WITH (FORMAT CSV, HEADER);
|
||||
|
||||
-- Import from CSV
|
||||
COPY users FROM '/tmp/users.csv' WITH (FORMAT CSV, HEADER);
|
||||
|
||||
-- Query to file
|
||||
COPY (SELECT * FROM users WHERE active = true)
|
||||
TO '/tmp/active_users.csv' WITH (FORMAT CSV, HEADER);
|
||||
```
|
||||
|
||||
### \copy (Client-side)
|
||||
```bash
|
||||
# Export (from psql)
|
||||
\copy users TO 'users.csv' WITH (FORMAT CSV, HEADER)
|
||||
|
||||
# Export query results
|
||||
\copy (SELECT * FROM users WHERE active = true) TO 'active.csv' CSV HEADER
|
||||
|
||||
# Import
|
||||
\copy users FROM 'users.csv' WITH (FORMAT CSV, HEADER)
|
||||
|
||||
# To stdout
|
||||
\copy users TO STDOUT CSV HEADER > users.csv
|
||||
```
|
||||
|
||||
### pg_dump / pg_restore
|
||||
```bash
|
||||
# Dump database
|
||||
pg_dump mydb > mydb.sql
|
||||
pg_dump -d mydb -Fc > mydb.dump # Custom format
|
||||
|
||||
# Dump specific table
|
||||
pg_dump -t users mydb > users.sql
|
||||
|
||||
# Schema only
|
||||
pg_dump -s mydb > schema.sql
|
||||
|
||||
# Data only
|
||||
pg_dump -a mydb > data.sql
|
||||
|
||||
# Restore
|
||||
psql mydb < mydb.sql
|
||||
pg_restore -d mydb mydb.dump
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### ~/.psqlrc
|
||||
```bash
|
||||
# Auto-loaded on psql startup
|
||||
\set QUIET ON
|
||||
|
||||
-- Prompt customization
|
||||
\set PROMPT1 '%n@%m:%>/%/%R%# '
|
||||
|
||||
-- Output settings
|
||||
\pset null '[NULL]'
|
||||
\pset border 2
|
||||
\pset linestyle unicode
|
||||
\pset expanded auto
|
||||
|
||||
-- Timing
|
||||
\timing ON
|
||||
|
||||
-- Pager
|
||||
\pset pager always
|
||||
|
||||
-- History
|
||||
\set HISTSIZE 10000
|
||||
|
||||
-- Custom shortcuts
|
||||
\set active_users 'SELECT * FROM users WHERE status = ''active'';'
|
||||
\set dbsize 'SELECT pg_size_pretty(pg_database_size(current_database()));'
|
||||
|
||||
\set QUIET OFF
|
||||
```
|
||||
|
||||
### Useful Aliases
|
||||
```bash
|
||||
# Add to ~/.psqlrc
|
||||
\set locks 'SELECT pid, usename, pg_blocking_pids(pid) as blocked_by, query FROM pg_stat_activity WHERE cardinality(pg_blocking_pids(pid)) > 0;'
|
||||
|
||||
\set activity 'SELECT pid, usename, state, query FROM pg_stat_activity WHERE state != ''idle'';'
|
||||
|
||||
\set table_sizes 'SELECT schemaname, tablename, pg_size_pretty(pg_total_relation_size(schemaname||''.''||tablename)) FROM pg_tables ORDER BY pg_total_relation_size(schemaname||''.''||tablename) DESC;'
|
||||
|
||||
\set index_usage 'SELECT schemaname, tablename, indexname, idx_scan FROM pg_stat_user_indexes ORDER BY idx_scan;'
|
||||
|
||||
# Usage: :locks, :activity, :table_sizes
|
||||
```
|
||||
|
||||
## Transactions
|
||||
|
||||
```sql
|
||||
-- Begin transaction
|
||||
BEGIN;
|
||||
|
||||
-- Or
|
||||
START TRANSACTION;
|
||||
|
||||
-- Savepoint
|
||||
SAVEPOINT sp1;
|
||||
|
||||
-- Rollback to savepoint
|
||||
ROLLBACK TO sp1;
|
||||
|
||||
-- Commit
|
||||
COMMIT;
|
||||
|
||||
-- Rollback
|
||||
ROLLBACK;
|
||||
```
|
||||
|
||||
## Performance Analysis
|
||||
|
||||
### EXPLAIN
|
||||
```sql
|
||||
-- Show query plan
|
||||
EXPLAIN SELECT * FROM users WHERE id = 1;
|
||||
|
||||
-- With execution
|
||||
EXPLAIN ANALYZE SELECT * FROM users WHERE age > 18;
|
||||
|
||||
-- Verbose
|
||||
EXPLAIN (ANALYZE, BUFFERS, VERBOSE)
|
||||
SELECT * FROM users WHERE active = true;
|
||||
```
|
||||
|
||||
### Current Activity
|
||||
```sql
|
||||
-- Active queries
|
||||
SELECT pid, usename, state, query
|
||||
FROM pg_stat_activity;
|
||||
|
||||
-- Long-running queries
|
||||
SELECT pid, now() - query_start AS duration, query
|
||||
FROM pg_stat_activity
|
||||
WHERE state != 'idle'
|
||||
ORDER BY duration DESC;
|
||||
|
||||
-- Blocking queries
|
||||
SELECT blocked.pid, blocking.pid AS blocking_pid,
|
||||
blocked.query AS blocked_query,
|
||||
blocking.query AS blocking_query
|
||||
FROM pg_stat_activity blocked
|
||||
JOIN pg_stat_activity blocking
|
||||
ON blocking.pid = ANY(pg_blocking_pids(blocked.pid));
|
||||
```
|
||||
|
||||
### Statistics
|
||||
```sql
|
||||
-- Database size
|
||||
SELECT pg_size_pretty(pg_database_size(current_database()));
|
||||
|
||||
-- Table sizes
|
||||
SELECT schemaname, tablename,
|
||||
pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) AS size
|
||||
FROM pg_tables
|
||||
ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC;
|
||||
|
||||
-- Index usage
|
||||
SELECT schemaname, tablename, indexname, idx_scan
|
||||
FROM pg_stat_user_indexes
|
||||
ORDER BY idx_scan;
|
||||
```
|
||||
|
||||
## User Management
|
||||
|
||||
```sql
|
||||
-- Create user
|
||||
CREATE USER appuser WITH PASSWORD 'secure_password';
|
||||
|
||||
-- Create superuser
|
||||
CREATE USER admin WITH PASSWORD 'password' SUPERUSER;
|
||||
|
||||
-- Alter user
|
||||
ALTER USER appuser WITH PASSWORD 'new_password';
|
||||
|
||||
-- Grant permissions
|
||||
GRANT CONNECT ON DATABASE mydb TO appuser;
|
||||
GRANT USAGE ON SCHEMA public TO appuser;
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON users TO appuser;
|
||||
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO appuser;
|
||||
|
||||
-- Default privileges
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA public
|
||||
GRANT SELECT ON TABLES TO appuser;
|
||||
|
||||
-- View permissions
|
||||
\dp users
|
||||
|
||||
-- Drop user
|
||||
DROP USER appuser;
|
||||
```
|
||||
|
||||
## Backup Patterns
|
||||
|
||||
```bash
|
||||
# Daily backup script
|
||||
#!/bin/bash
|
||||
DATE=$(date +%Y%m%d)
|
||||
pg_dump -Fc mydb > /backups/mydb_$DATE.dump
|
||||
|
||||
# Restore latest
|
||||
pg_restore -d mydb /backups/mydb_latest.dump
|
||||
|
||||
# Backup all databases
|
||||
pg_dumpall > /backups/all_databases.sql
|
||||
|
||||
# Backup specific schema
|
||||
pg_dump -n public mydb > public_schema.sql
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Connection Issues
|
||||
```bash
|
||||
# Test connection
|
||||
psql -h hostname -U username -d postgres -c "SELECT 1;"
|
||||
|
||||
# Check pg_hba.conf
|
||||
# /var/lib/postgresql/data/pg_hba.conf
|
||||
|
||||
# Verbose connection
|
||||
psql -h hostname -d mydb --echo-all
|
||||
```
|
||||
|
||||
### Performance Issues
|
||||
```sql
|
||||
-- Enable slow query logging
|
||||
ALTER DATABASE mydb SET log_min_duration_statement = 100;
|
||||
|
||||
-- Check cache hit ratio
|
||||
SELECT
|
||||
sum(heap_blks_read) as heap_read,
|
||||
sum(heap_blks_hit) as heap_hit,
|
||||
sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) AS ratio
|
||||
FROM pg_statio_user_tables;
|
||||
|
||||
-- Find slow queries
|
||||
SELECT query, mean_exec_time, calls
|
||||
FROM pg_stat_statements
|
||||
ORDER BY mean_exec_time DESC
|
||||
LIMIT 10;
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use .pgpass** for credential management
|
||||
2. **Set ON_ERROR_STOP** in scripts
|
||||
3. **Use transactions** for multi-statement changes
|
||||
4. **Test with EXPLAIN** before running expensive queries
|
||||
5. **Use \timing** to measure query performance
|
||||
6. **Configure ~/.psqlrc** for productivity
|
||||
7. **Use variables** for dynamic queries
|
||||
8. **Log sessions** with -L for auditing
|
||||
9. **Use \copy** instead of COPY for client operations
|
||||
10. **Regular backups** with pg_dump
|
||||
Reference in New Issue
Block a user