Heroku Postgres #

Postgres 概述 #

Heroku Postgres 是 Heroku 提供的托管 PostgreSQL 数据库服务,基于世界上最先进的开源数据库构建。

特点 #

特点 说明
完全托管 自动备份、更新、监控
高可用 多可用区部署
可扩展 轻松升级计划
安全 加密连接、行级安全
兼容 标准 PostgreSQL

计划类型 #

计划 存储 内存 连接数 价格/月
Mini 1GB 共享 20 $5
Basic 4GB 共享 20 $9
Standard-0 8GB 512MB 120 $50
Standard-2 32GB 2GB 400 $200
Premium-0 16GB 1.5GB 500 $200
Premium-2 64GB 6GB 800 $800

创建数据库 #

使用 CLI 创建 #

bash
# 创建 Mini 数据库
heroku addons:create heroku-postgresql:mini

# 创建指定计划
heroku addons:create heroku-postgresql:standard-0

# 指定应用名称
heroku addons:create heroku-postgresql:mini --app myapp

# 指定版本
heroku addons:create heroku-postgresql:mini --version=16

查看数据库信息 #

bash
# 查看数据库信息
heroku pg:info

# 输出示例
# === DATABASE_URL, HEROKU_POSTGRESQL_IVORY_URL
# Plan:        Mini
# Status:      Available
# Connections: 1/20
# PG Version:  16.2
# Created:     2024-01-15 10:00 UTC
# Data Size:   10.2 MB
# Tables:      5
# Rows:        1000/10000 (Row limit)
# Fork/Follow: Unsupported
# Rollback:    Unsupported
# Add-on:      postgresql-round-12345

数据库 URL #

bash
# 查看数据库 URL
heroku config:get DATABASE_URL

# 输出格式
# postgres://user:password@host:port/database

# 多个数据库
heroku config | grep HEROKU_POSTGRESQL

连接数据库 #

Node.js 连接 #

javascript
const { Pool } = require('pg');

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  ssl: {
    rejectUnauthorized: false
  }
});

// 查询示例
const result = await pool.query('SELECT * FROM users WHERE id = $1', [userId]);
console.log(result.rows);

// 关闭连接池
await pool.end();

Python 连接 #

python
import os
import psycopg2
from psycopg2.extras import RealDictCursor

# 连接数据库
conn = psycopg2.connect(
    os.environ['DATABASE_URL'],
    sslmode='require',
    cursor_factory=RealDictCursor
)

# 查询示例
cur = conn.cursor()
cur.execute('SELECT * FROM users WHERE id = %s', (user_id,))
rows = cur.fetchall()

# 关闭连接
cur.close()
conn.close()

Ruby 连接 #

ruby
require 'pg'

# 连接数据库
conn = PG.connect(ENV['DATABASE_URL'], sslmode: 'require')

# 查询示例
result = conn.exec_params('SELECT * FROM users WHERE id = $1', [user_id])
result.each do |row|
  puts row
end

# 关闭连接
conn.close

使用连接池 #

javascript
const { Pool } = require('pg');

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  ssl: { rejectUnauthorized: false },
  max: 10,                    // 最大连接数
  idleTimeoutMillis: 30000,   // 空闲超时
  connectionTimeoutMillis: 2000 // 连接超时
});

// 使用连接池
app.get('/users/:id', async (req, res) => {
  try {
    const result = await pool.query(
      'SELECT * FROM users WHERE id = $1',
      [req.params.id]
    );
    res.json(result.rows[0]);
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: 'Database error' });
  }
});

数据库管理 #

访问数据库 #

bash
# 进入 psql 命令行
heroku pg:psql

# 指定数据库
heroku pg:psql DATABASE_URL

# 执行 SQL 文件
heroku pg:psql < schema.sql

# 执行单条 SQL
heroku pg:psql -c "SELECT COUNT(*) FROM users"

查看表结构 #

bash
# 进入 psql 后
\dt          # 列出所有表
\d users     # 查看 users 表结构
\di          # 列出所有索引
\df          # 列出所有函数
\q           # 退出

数据迁移 #

javascript
// 使用 node-pg-migrate
// package.json
{
  "scripts": {
    "migrate": "node-pg-migrate up",
    "migrate:down": "node-pg-migrate down",
    "migrate:create": "node-pg-migrate create"
  }
}

// 创建迁移
// npm run migrate:create add users table

// migrations/20240115000000_add-users-table.js
exports.up = (pgm) => {
  pgm.createTable('users', {
    id: { type: 'serial', primaryKey: true },
    email: { type: 'varchar(255)', notNull: true, unique: true },
    name: { type: 'varchar(255)' },
    created_at: { type: 'timestamp', default: pgm.func('now()') }
  });
};

exports.down = (pgm) => {
  pgm.dropTable('users');
};

数据库备份 #

bash
# 创建备份
heroku pg:backups:capture

# 查看备份列表
heroku pg:backups

# 输出示例
# === Backups
# ID    Created at               Status                              Size    Database
# b001  2024-01-15 10:00:00 UTC  Completed 2024-01-15 10:01:00 UTC  10.2MB  DATABASE_URL

# 下载备份
heroku pg:backups:download b001

# 恢复备份
heroku pg:backups:restore b001 --app myapp --confirm myapp

# 设置自动备份
heroku pg:backups:schedule DATABASE_URL --at '02:00 America/Los_Angeles'

数据库监控 #

查看数据库状态 #

bash
# 详细信息
heroku pg:info

# 查看连接数
heroku pg:connections

# 查看锁
heroku pg:locks

# 查看等待事件
heroku pg:wait-events

性能分析 #

bash
# 查看慢查询
heroku pg:psql -c "SELECT * FROM pg_stat_statements ORDER BY total_time DESC LIMIT 10"

# 查看表大小
heroku pg:psql -c "SELECT relname, pg_size_pretty(pg_total_relation_size(relid)) FROM pg_catalog.pg_statio_user_tables ORDER BY pg_total_relation_size(relid) DESC"

# 查看索引使用情况
heroku pg:psql -c "SELECT indexrelname, idx_scan FROM pg_stat_user_indexes ORDER BY idx_scan"

使用 Data Clips #

bash
# Data Clips 是 Heroku 提供的 SQL 查询结果分享功能
# 在 Dashboard 中访问:
# https://data.heroku.com/dataclips

数据库扩展 #

升级计划 #

bash
# 查看当前计划
heroku pg:info

# 升级到更高计划
heroku addons:upgrade heroku-postgresql-standard-0

# 降级计划
heroku addons:downgrade heroku-postgresql-basic

扩展存储 #

bash
# 查看存储使用情况
heroku pg:info

# 升级到更大存储的计划
heroku addons:upgrade heroku-postgresql-standard-2

数据库复制 #

Follower 数据库 #

bash
# 创建只读副本
heroku addons:create heroku-postgresql:standard-0 --follow DATABASE_URL

# 查看复制状态
heroku pg:info

# 输出示例
# === HEROKU_POSTGRESQL_SILVER_URL
# Plan:        Standard 0
# Status:      Available
# Following:   DATABASE_URL (DATABASE_URL)
# Behind By:   0 sec

数据库分叉 #

bash
# 创建数据库分叉(用于测试)
heroku addons:create heroku-postgresql:standard-0 --fork DATABASE_URL

# 指定时间点分叉
heroku addons:create heroku-postgresql:standard-0 --fork DATABASE_URL --at "2024-01-15 10:00:00"

数据库安全 #

SSL 连接 #

javascript
// 强制 SSL 连接
const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  ssl: {
    rejectUnauthorized: false
  }
});

连接限制 #

bash
# 查看连接限制
heroku pg:info

# Mini: 20 连接
# Basic: 20 连接
# Standard-0: 120 连接
# Standard-2: 400 连接

# 使用连接池避免连接数耗尽

凭证管理 #

bash
# 查看凭证
heroku pg:credentials:url

# 轮换凭证
heroku pg:credentials:rotate

# 创建只读用户
heroku pg:credentials:create readonly

常用操作 #

导入导出数据 #

bash
# 导出数据
pg_dump $DATABASE_URL > backup.sql

# 导入数据
heroku pg:psql < backup.sql

# 使用 CSV 导入
heroku pg:psql -c "COPY users FROM '/tmp/users.csv' WITH CSV HEADER"

# 导出为 CSV
heroku pg:psql -c "COPY users TO STDOUT WITH CSV HEADER" > users.csv

重置数据库 #

bash
# 重置数据库(删除所有数据)
heroku pg:reset DATABASE_URL --confirm myapp

# 警告:此操作不可逆!

数据库迁移 #

bash
# 从其他数据库迁移到 Heroku Postgres
heroku pg:push mylocaldb DATABASE_URL --app myapp

# 从 Heroku Postgres 迁移到本地
heroku pg:pull DATABASE_URL mylocaldb --app myapp

性能优化 #

索引优化 #

sql
-- 创建索引
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_created_at ON users(created_at);

-- 查看索引使用情况
SELECT indexrelname, idx_scan, idx_tup_read, idx_tup_fetch 
FROM pg_stat_user_indexes;

-- 删除未使用的索引
DROP INDEX idx_unused;

查询优化 #

sql
-- 使用 EXPLAIN 分析查询
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'test@example.com';

-- 创建部分索引
CREATE INDEX idx_active_users ON users(email) WHERE active = true;

-- 使用连接池
-- 使用预处理语句

连接池配置 #

javascript
const { Pool } = require('pg');

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  ssl: { rejectUnauthorized: false },
  max: 10,                      // 最大连接数
  min: 2,                       // 最小连接数
  idleTimeoutMillis: 30000,     // 空闲超时
  connectionTimeoutMillis: 2000 // 连接超时
});

故障排查 #

连接问题 #

bash
# 检查数据库状态
heroku pg:info

# 检查连接数
heroku pg:connections

# 查看错误日志
heroku logs --tail | grep postgres

性能问题 #

bash
# 查看慢查询
heroku pg:psql -c "SELECT * FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 10"

# 查看锁
heroku pg:locks

# 查看等待事件
heroku pg:wait-events

存储问题 #

bash
# 查看存储使用
heroku pg:info

# 清理不需要的数据
heroku pg:psql -c "VACUUM FULL ANALYZE"

# 升级存储计划
heroku addons:upgrade heroku-postgresql-standard-2

下一步 #

PostgreSQL 掌握后,接下来学习 数据库迁移 了解数据迁移和备份恢复!

最后更新:2026-03-28