PlanetScale 性能优化 #

本章将介绍如何优化 PlanetScale 数据库性能,包括查询优化、索引策略、监控告警等最佳实践。

性能基础 #

PlanetScale 性能特点 #

text
┌─────────────────────────────────────────────────────────────┐
│                    性能架构                                   │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   优势:                                                    │
│                                                             │
│   ✅ 自动扩展                                               │
│      - 读取自动负载均衡                                    │
│      - 无需手动扩容                                        │
│                                                             │
│   ✅ 高可用                                                 │
│      - 主从复制                                            │
│      - 自动故障转移                                        │
│                                                             │
│   ✅ 优化网络                                               │
│      - 全球边缘节点                                        │
│      - 低延迟连接                                          │
│                                                             │
│   注意事项:                                                │
│   ⚠️ 查询优化仍需手动处理                                  │
│   ⚠️ 索引设计需要规划                                      │
│   ⚠️ 连接池需要合理配置                                    │
│                                                             │
└─────────────────────────────────────────────────────────────┘

性能指标 #

text
┌─────────────────────────────────────────────────────────────┐
│                    关键性能指标                               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   查询性能:                                                │
│   ├── 查询延迟 (Latency)                                   │
│   ├── 查询吞吐量 (QPS)                                     │
│   └── 慢查询比例                                           │
│                                                             │
│   连接性能:                                                │
│   ├── 连接延迟                                             │
│   ├── 连接池使用率                                         │
│   └── 连接错误率                                           │
│                                                             │
│   资源使用:                                                │
│   ├── 行读取量                                             │
│   ├── 行写入量                                             │
│   └── 存储使用量                                           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

查询优化 #

查询分析 #

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

-- EXPLAIN 输出示例
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | users | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 1000 |    10.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+

-- 使用 EXPLAIN ANALYZE(如果支持)
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'test@example.com';

查询优化技巧 #

text
┌─────────────────────────────────────────────────────────────┐
│                    查询优化建议                               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   1. 选择合适的列                                           │
│      ❌ SELECT * FROM users                                │
│      ✅ SELECT id, name, email FROM users                  │
│                                                             │
│   2. 使用索引列过滤                                         │
│      ❌ WHERE YEAR(created_at) = 2024                      │
│      ✅ WHERE created_at >= '2024-01-01'                   │
│                                                             │
│   3. 避免 SELECT DISTINCT                                  │
│      ❌ SELECT DISTINCT name FROM users                    │
│      ✅ SELECT name FROM users GROUP BY name               │
│                                                             │
│   4. 使用 LIMIT                                            │
│      ❌ SELECT * FROM users                                │
│      ✅ SELECT * FROM users LIMIT 100                      │
│                                                             │
│   5. 避免 OR 条件                                          │
│      ❌ WHERE status = 'active' OR status = 'pending'      │
│      ✅ WHERE status IN ('active', 'pending')              │
│                                                             │
│   6. 使用 JOIN 代替子查询                                   │
│      ❌ SELECT * FROM users WHERE id IN (SELECT user_id...)│
│      ✅ SELECT users.* FROM users JOIN orders...           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

分页优化 #

sql
-- 传统分页(大偏移量性能差)
SELECT * FROM users ORDER BY id LIMIT 10000, 20;

-- 游标分页(推荐)
SELECT * FROM users WHERE id > 10000 ORDER BY id LIMIT 20;

-- 使用覆盖索引
SELECT id FROM users ORDER BY created_at LIMIT 10000, 20;
SELECT * FROM users WHERE id IN (...);

批量操作优化 #

sql
-- 批量插入
INSERT INTO users (name, email) VALUES
  ('User 1', 'user1@example.com'),
  ('User 2', 'user2@example.com'),
  ('User 3', 'user3@example.com');

-- 批量更新
UPDATE users SET status = 'active' 
WHERE id IN (1, 2, 3, 4, 5);

-- 使用 CASE 批量更新不同值
UPDATE users SET status = CASE id
  WHEN 1 THEN 'active'
  WHEN 2 THEN 'inactive'
  WHEN 3 THEN 'pending'
END
WHERE id IN (1, 2, 3);

索引优化 #

索引类型 #

text
┌─────────────────────────────────────────────────────────────┐
│                    索引类型                                   │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   主键索引(Primary Key)                                   │
│   ├── 自动创建                                             │
│   ├── 唯一且非空                                           │
│   └── 聚簇索引                                             │
│                                                             │
│   唯一索引(Unique Index)                                  │
│   ├── 确保值唯一                                           │
│   ├── 允许 NULL                                            │
│   └── CREATE UNIQUE INDEX idx_email ON users(email)        │
│                                                             │
│   普通索引(Index)                                         │
│   ├── 加速查询                                             │
│   ├── 允许重复                                             │
│   └── CREATE INDEX idx_status ON users(status)             │
│                                                             │
│   复合索引(Composite Index)                               │
│   ├── 多列组合                                             │
│   ├── 遵循最左前缀                                         │
│   └── CREATE INDEX idx_status_created ON users(status, created_at)│
│                                                             │
│   全文索引(Fulltext Index)                                │
│   ├── 文本搜索                                             │
│   └── CREATE FULLTEXT INDEX idx_content ON posts(content)  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

索引设计原则 #

text
┌─────────────────────────────────────────────────────────────┐
│                    索引设计原则                               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   1. 选择性高的列优先                                       │
│      - 唯一值多的列                                        │
│      - 区分度高                                            │
│                                                             │
│   2. 复合索引顺序                                           │
│      - 高选择性列在前                                      │
│      - 范围查询列在后                                      │
│      - 遵循最左前缀原则                                    │
│                                                             │
│   3. 覆盖索引                                               │
│      - 索引包含查询所需列                                  │
│      - 避免回表                                            │
│                                                             │
│   4. 避免过度索引                                           │
│      - 索引占用空间                                        │
│      - 影响写入性能                                        │
│      - 维护成本                                            │
│                                                             │
│   5. 定期审查索引                                           │
│      - 删除未使用索引                                      │
│      - 优化冗余索引                                        │
│                                                             │
└─────────────────────────────────────────────────────────────┘

索引示例 #

sql
-- 单列索引
CREATE INDEX idx_email ON users(email);

-- 复合索引(注意顺序)
CREATE INDEX idx_status_created ON users(status, created_at);

-- 覆盖索引
CREATE INDEX idx_covering ON users(status, created_at, name);

-- 查看索引使用情况
SHOW INDEX FROM users;

-- 删除索引
DROP INDEX idx_email ON users;

-- 分析索引使用
EXPLAIN SELECT * FROM users WHERE status = 'active' AND created_at > '2024-01-01';

索引使用检查 #

sql
-- 检查索引是否被使用
EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';

-- type 列说明:
-- ALL: 全表扫描(需要优化)
-- index: 索引扫描
-- range: 范围扫描
-- ref: 索引查找
-- const: 主键/唯一索引查找(最优)

连接池优化 #

连接池配置 #

text
┌─────────────────────────────────────────────────────────────┐
│                    连接池配置建议                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   Node.js (mysql2):                                        │
│   {                                                         │
│     connectionLimit: 10,      // 连接池大小               │
│     waitForConnections: true, // 等待可用连接             │
│     queueLimit: 0,            // 队列无限制               │
│     connectTimeout: 10000,    // 连接超时 10s             │
│     acquireTimeout: 30000     // 获取连接超时 30s         │
│   }                                                         │
│                                                             │
│   Python (SQLAlchemy):                                     │
│   {                                                         │
│     pool_size: 10,            // 连接池大小               │
│     max_overflow: 5,          // 溢出连接数               │
│     pool_timeout: 30,         // 获取超时                 │
│     pool_recycle: 3600        // 连接回收时间             │
│   }                                                         │
│                                                             │
│   Go (sql.DB):                                             │
│   db.SetMaxOpenConns(10)      // 最大打开连接              │
│   db.SetMaxIdleConns(5)       // 最大空闲连接              │
│   db.SetConnMaxLifetime(time.Hour)  // 连接最大生命周期   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

连接池监控 #

javascript
import mysql from 'mysql2/promise';

const pool = mysql.createPool({
  host: 'aws.connect.psdb.cloud',
  user: 'abc123',
  password: 'pscale_pw_xxx',
  database: 'my-database',
  ssl: { rejectUnauthorized: true },
  connectionLimit: 10
});

setInterval(() => {
  const poolInfo = pool.pool;
  console.log({
    total: poolInfo._allConnections.length,
    free: poolInfo._freeConnections.length,
    waiting: poolInfo._connectionQueue.length
  });
}, 60000);

监控与告警 #

Web 控制台监控 #

text
┌─────────────────────────────────────────────────────────────┐
│                    监控面板                                   │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   Overview 页面:                                           │
│   ├── 存储使用量                                           │
│   ├── 行读取统计                                           │
│   ├── 行写入统计                                           │
│   └── 连接数统计                                           │
│                                                             │
│   Insights 页面:                                           │
│   ├── 慢查询列表                                           │
│   ├── 查询性能分析                                         │
│   └── 优化建议                                             │
│                                                             │
│   告警设置:                                                │
│   ├── 存储使用超过阈值                                     │
│   ├── 行读取接近限制                                       │
│   └── 慢查询数量增加                                       │
│                                                             │
└─────────────────────────────────────────────────────────────┘

慢查询分析 #

sql
-- 查找慢查询
SELECT * FROM users WHERE name LIKE '%test%';

-- 优化方案
-- 1. 添加索引
CREATE INDEX idx_name ON users(name);

-- 2. 使用前缀匹配
SELECT * FROM users WHERE name LIKE 'test%';

-- 3. 使用全文索引
CREATE FULLTEXT INDEX idx_name_ft ON users(name);
SELECT * FROM users WHERE MATCH(name) AGAINST('test');

性能监控脚本 #

javascript
import mysql from 'mysql2/promise';

async function monitorPerformance() {
  const connection = await mysql.createConnection(process.env.DATABASE_URL);

  const [tables] = await connection.execute(`
    SELECT 
      table_name,
      table_rows,
      ROUND(data_length / 1024 / 1024, 2) as data_mb,
      ROUND(index_length / 1024 / 1024, 2) as index_mb
    FROM information_schema.tables
    WHERE table_schema = DATABASE()
  `);

  console.table(tables);

  await connection.end();
}

monitorPerformance();

缓存策略 #

应用层缓存 #

text
┌─────────────────────────────────────────────────────────────┐
│                    缓存架构                                   │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   请求流程:                                                │
│                                                             │
│   ┌─────────┐     ┌─────────┐     ┌─────────────┐         │
│   │  客户端  │────>│  缓存   │────>│ PlanetScale │         │
│   └─────────┘     └─────────┘     └─────────────┘         │
│                         │                                   │
│                         │ 命中                              │
│                         ▼                                   │
│                    直接返回                                 │
│                                                             │
│   缓存策略:                                                │
│   ├── Redis / Memcached                                   │
│   ├── CDN 缓存静态数据                                     │
│   └── 应用内存缓存                                         │
│                                                             │
│   适用场景:                                                │
│   - 热点数据                                               │
│   - 读多写少                                               │
│   - 实时性要求不高                                         │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Redis 缓存示例 #

javascript
import Redis from 'ioredis';
import mysql from 'mysql2/promise';

const redis = new Redis(process.env.REDIS_URL);
const pool = mysql.createPool(process.env.DATABASE_URL);

async function getUser(id) {
  const cacheKey = `user:${id}`;

  const cached = await redis.get(cacheKey);
  if (cached) {
    return JSON.parse(cached);
  }

  const [rows] = await pool.execute(
    'SELECT * FROM users WHERE id = ?',
    [id]
  );

  if (rows[0]) {
    await redis.setex(cacheKey, 3600, JSON.stringify(rows[0]));
  }

  return rows[0];
}

async function updateUser(id, data) {
  await pool.execute(
    'UPDATE users SET name = ? WHERE id = ?',
    [data.name, id]
  );

  await redis.del(`user:${id}`);
}

性能优化清单 #

text
┌─────────────────────────────────────────────────────────────┐
│                    优化检查清单                               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   查询优化:                                                │
│   □ 使用 EXPLAIN 分析慢查询                               │
│   □ 避免 SELECT *                                         │
│   □ 使用 LIMIT 限制结果集                                 │
│   □ 优化 JOIN 操作                                        │
│   □ 使用游标分页                                          │
│                                                             │
│   索引优化:                                                │
│   □ 为常用查询条件添加索引                                │
│   □ 使用复合索引优化多条件查询                            │
│   □ 删除未使用的索引                                      │
│   □ 检查索引选择性                                        │
│                                                             │
│   连接优化:                                                │
│   □ 配置合理的连接池大小                                  │
│   □ 监控连接池使用率                                      │
│   □ 处理连接泄漏                                          │
│                                                             │
│   缓存优化:                                                │
│   □ 为热点数据添加缓存                                    │
│   □ 设置合理的缓存过期时间                                │
│   □ 处理缓存失效                                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

下一步 #

现在你已经掌握了性能优化,接下来学习 安全配置,了解如何保护你的 PlanetScale 数据库!

最后更新:2026-03-29