Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save CodeBradley/ca14eef7cb83c4fcf2ac5f60bad46133 to your computer and use it in GitHub Desktop.

Select an option

Save CodeBradley/ca14eef7cb83c4fcf2ac5f60bad46133 to your computer and use it in GitHub Desktop.
MySQL to PostgreSQL: The Ultimate Transition Guide

MySQL to PostgreSQL: The Ultimate Transition Guide

As a MySQL developer venturing into PostgreSQL territory, you're about to discover a database system that shares many similarities with MySQL while offering a distinctly different philosophy and feature set. This guide will walk you through the major architectural differences before diving into the intricate details that make PostgreSQL unique.

Table of Contents


Fundamental Philosophy and Architecture

Storage Engines vs. Single Engine

MySQL:

CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(100)
) ENGINE=InnoDB;

PostgreSQL:

CREATE TABLE users (
    id INTEGER PRIMARY KEY,
    name VARCHAR(100)
);

MVCC Implementation Details

  • MySQL (InnoDB): Uses undo logs.
  • PostgreSQL: Uses tuple versioning and needs VACUUM.

Concurrency and Transaction Model

Isolation Levels

MySQL: REPEATABLE READ by default
PostgreSQL: READ COMMITTED by default

Locking Behavior

MySQL Example:

-- Session 1
START TRANSACTION;
SELECT * FROM orders WHERE status = 'pending' FOR UPDATE;

-- Session 2
INSERT INTO orders (status) VALUES ('pending');

PostgreSQL Example:

-- Session 1
BEGIN;
SELECT * FROM orders WHERE status = 'pending' FOR UPDATE;

-- Session 2
INSERT INTO orders (status) VALUES ('pending');

Deadlock Detection

  • PostgreSQL has detailed logs and cross-object detection.

Data Types and Type System

Rich Built-in Types

Arrays

CREATE TABLE metrics (
    id SERIAL PRIMARY KEY,
    values INTEGER[],
    tags TEXT[]
);

JSON/JSONB

CREATE TABLE events (
    id SERIAL PRIMARY KEY,
    data JSONB
);

CREATE INDEX idx_data_gin ON events USING GIN (data);

Custom Types

CREATE TYPE address AS (
    street TEXT,
    city TEXT,
    country TEXT
);

Type Casting

MySQL (implicit):

SELECT * FROM users WHERE id = '123';

PostgreSQL (explicit):

SELECT * FROM users WHERE id = '123'::INTEGER;

SQL Compliance and Syntax Differences

Case Sensitivity

PostgreSQL identifiers are lowercase unless quoted. Strings are case-sensitive.

CREATE TABLE "MyTable" (id INTEGER);
SELECT * FROM "MyTable";

Boolean Handling

MySQL:

is_enabled TINYINT(1)

PostgreSQL:

is_enabled BOOLEAN

LIMIT/OFFSET Syntax

SELECT * FROM users OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;

Indexing Capabilities

Index Types

PostgreSQL supports:

  • B-tree
  • GIN
  • GiST
  • BRIN
  • Hash

Partial Indexes

CREATE INDEX idx_active_users ON users(email) 
WHERE status = 'active';

Expression Indexes

CREATE INDEX idx_lower_email ON users(LOWER(email));

Performance Characteristics

Query Planning

PostgreSQL:

EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) SELECT ...

Statistics

ALTER TABLE large_table ALTER COLUMN important_column SET STATISTICS 1000;

Parallel Execution

SET max_parallel_workers_per_gather = 4;

Replication and High Availability

PostgreSQL Features

  • WAL-based streaming
  • Logical replication
CREATE PUBLICATION my_pub FOR TABLE users, orders;
CREATE SUBSCRIPTION my_sub CONNECTION '...' PUBLICATION my_pub;

Security Features

Row-Level Security

ALTER TABLE orders ENABLE ROW LEVEL SECURITY;

CREATE POLICY user_orders ON orders
    FOR ALL
    TO application_role
    USING (user_id = current_user_id());

Authentication

  • PostgreSQL supports SCRAM, cert, LDAP, etc.

Extensions and Customizability

Extensions

CREATE EXTENSION postgis;
CREATE EXTENSION pg_stat_statements;

Custom Functions

CREATE FUNCTION calculate_tax(amount DECIMAL) 
RETURNS DECIMAL AS $$
DECLARE
    tax_rate CONSTANT DECIMAL := 0.08;
BEGIN
    RETURN amount * tax_rate;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
CREATE FUNCTION sentiment_analysis(text_input TEXT) 
RETURNS TEXT AS $$
    import textblob
    blob = textblob.TextBlob(text_input)
    return 'positive' if blob.sentiment.polarity > 0 else 'negative'
$$ LANGUAGE plpython3u;

Operational Differences

Maintenance Operations

VACUUM (FULL, ANALYZE) users;

Configuration Management

SHOW work_mem;
SET work_mem = '256MB';

System Catalogs

SELECT indexname, indexdef FROM pg_indexes WHERE tablename = 'users';

Migration Considerations

AUTO_INCREMENT to SERIAL

MySQL:

id INT AUTO_INCREMENT PRIMARY KEY

PostgreSQL:

id SERIAL PRIMARY KEY

Date Formatting

MySQL:

SELECT DATE_FORMAT(NOW(), '%Y-%m-%d');

PostgreSQL:

SELECT TO_CHAR(NOW(), 'YYYY-MM-DD');

GROUP BY Differences

MySQL:

SELECT id, name, COUNT(*) FROM users GROUP BY id;

PostgreSQL:

SELECT id, name, COUNT(*) FROM users GROUP BY id, name;

Conclusion

PostgreSQL offers a feature-rich environment that may initially seem overwhelming coming from MySQL. The strict type system, MVCC implementation, and extensive feature set require a different mindset but provide powerful capabilities for complex applications.

The key to successfully transitioning from MySQL to PostgreSQL is understanding these fundamental differences and embracing PostgreSQL's philosophy of extensibility, standards compliance, and data integrity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment