正在加载,请稍候…

PlanetScale and Vitess: MySQL Scaling with Database Branching

Use PlanetScale for horizontally scalable MySQL — database branching workflow, non-blocking schema changes, deploy requests, and Vitess's connection pooling.

PlanetScale Architecture

PlanetScale is MySQL-compatible database built on Vitess (used by YouTube, Slack, GitHub). It adds:

  • Database branches: Like git, but for schemas
  • Non-blocking schema changes: ALTER TABLE without locks
  • Horizontal sharding: Auto-scale to millions of queries/sec

Branching Workflow

# Install PlanetScale CLI
brew install planetscale/tap/pscale

# Connect to branch
pscale shell myapp main

# Create development branch
pscale branch create myapp add-user-avatar

# Connect to branch
pscale connect myapp add-user-avatar --port 3309

# Make schema changes on branch
mysql -h 127.0.0.1 -P 3309 -u root myapp
ALTER TABLE users ADD COLUMN avatar_url VARCHAR(500);
CREATE INDEX idx_users_email ON users (email);

# Create deploy request (like a pull request)
pscale deploy-request create myapp add-user-avatar

# After review, deploy to main (non-blocking!)
pscale deploy-request deploy myapp 1

Connection in Node.js

import mysql2 from 'mysql2/promise'

const pool = mysql2.createPool({
  host: process.env.DATABASE_HOST,
  database: process.env.DATABASE_NAME,
  username: process.env.DATABASE_USERNAME,
  password: process.env.DATABASE_PASSWORD,
  ssl: { rejectUnauthorized: true },
  pool: {
    min: 2,
    max: 10,
    acquireTimeout: 30000,
  },
})

// Or use the PlanetScale serverless driver (edge-compatible)
import { connect } from '@planetscale/database'

const conn = connect({
  host: process.env.DATABASE_HOST,
  username: process.env.DATABASE_USERNAME,
  password: process.env.DATABASE_PASSWORD,
})

const results = await conn.execute('SELECT * FROM users WHERE id = ?', [userId])

Vitess Limitations

Foreign keys are disabled in Vitess (use application-level integrity):

// Instead of foreign key constraint, validate in application
async function createPost(userId: string, title: string) {
  // Check user exists
  const user = await db.query('SELECT id FROM users WHERE id = ?', [userId])
  if (!user.rows.length) throw new Error('User not found')
  
  return db.query('INSERT INTO posts (user_id, title) VALUES (?, ?)', [userId, title])
}

Schema Changes in Production

PlanetScale uses Vitess's Online DDL:

-- These run online, no blocking
ALTER TABLE orders ADD COLUMN tracking_number VARCHAR(100);
ALTER TABLE products MODIFY COLUMN description TEXT;
CREATE INDEX idx_orders_date ON orders (created_at);
DROP INDEX idx_old_unused ON products;

Horizontal Sharding

-- Define a sharding key in schema
CREATE TABLE orders (
  id BIGINT NOT NULL,
  customer_id BIGINT NOT NULL,  -- This becomes the shard key
  amount DECIMAL(10,2),
  PRIMARY KEY (customer_id, id)  -- Customer ID in PK for co-location
) ENGINE=InnoDB;

Performance Numbers

PlanetScale/Vitess handles:

  • 1.5 million QPS (YouTube in 2019)
  • Unlimited horizontal scale
  • Zero-downtime schema changes on tables with billions of rows