NewSQL databases combine the ACID guarantees of traditional databases with the horizontal scaling of NoSQL. This guide covers NewSQL concepts and leading implementations.
Understanding NewSQL
The Problem
traditional_sql:
pros: "ACID, mature, well-understood"
cons: "Can't scale horizontally"
nosql:
pros: "Horizontal scaling, high throughput"
cons: "Weak consistency, no ACID"
newsql:
goal: "Best of both worlds"
features:
- "Distributed architecture"
- "ACID transactions"
- "Horizontal scaling"
- "SQL interface"
CockroachDB
Architecture
cockroachdb:
architecture: "Distributed, multi-active"
consensus: "Raft consensus"
replication: "3-way minimum"
sharding: "Range-based automatic"
sql: "PostgreSQL-compatible"
# Connect to CockroachDB
import psycopg2
conn = psycopg2.connect(
host="localhost",
port=26257,
database="defaultdb",
user="root",
password="password"
)
# Create distributed table
cur = conn.cursor()
# Geo-partitioned table
cur.execute("""
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email STRING,
region STRING,
created_at TIMESTAMP DEFAULT now()
) PARTITION BY LIST (region) (
PARTITION us VALUES IN ('us-east', 'us-west'),
PARTITION eu VALUES IN ('eu-west', 'eu-east'),
PARTITION default VALUES IN (DEFAULT)
)
""")
# Transaction with retry
def transfer_funds(conn, from_id, to_id, amount):
with conn.cursor() as cur:
while True:
try:
cur.execute("BEGIN")
cur.execute("""
UPDATE accounts
SET balance = balance - %s
WHERE id = %s AND balance >= %s
""", (amount, from_id, amount))
if cur.rowcount == 0:
cur.execute("ROLLBACK")
return False, "Insufficient funds"
cur.execute("""
UPDATE accounts
SET balance = balance + %s
WHERE id = %s
""", (amount, to_id))
cur.execute("COMMIT")
return True, "Transfer complete"
except psycopg2.errors.SerializationFailure:
cur.execute("ROLLBACK")
continue
TiDB
Architecture
tidb:
components:
- "TiDB Server (SQL layer)"
- "TiKV (storage engine)"
- "PD (placement driver)"
consensus: "Raft"
features:
- "HTAP (Hybrid Transactional/Analytical)"
- "Automatic sharding"
- "Strong consistency"
# TiDB with Python
import pymysql
conn = pymysql.connect(
host="localhost",
port=4000,
user="root",
password="password",
database="test"
)
cur = conn.cursor()
# Create table with AUTO_RANDOM for distributed IDs
cur.execute("""
CREATE TABLE orders (
id BIGINT PRIMARY KEY AUTO_RANDOM,
customer_id BIGINT NOT NULL,
total DECIMAL(10,2),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
# Distributed transaction (using optimistic locking)
cur.execute("""
SELECT id, balance, version
FROM accounts
WHERE id IN (%s, %s)
FOR UPDATE
""", (from_id, to_id))
# Update with version check
cur.execute("""
UPDATE accounts
SET balance = balance - %s, version = version + 1
WHERE id = %s AND version = %s
""", (amount, from_id, from_version))
if cur.rowcount == 0:
print("Concurrent modification detected")
Google Spanner
Architecture
spanner:
provider: "Google Cloud"
consistency: "TrueTime (GPS + atomic clocks)"
features:
- "Globally distributed"
- "Strong consistency"
- "Automatic sharding"
- "Schema changes online"
# Google Spanner with Python
from google.cloud import spanner
client = spanner.Client(instance_id, database_id)
# Transaction with read-your-writes consistency
def update_inventory(instance_id, product_id, quantity):
transaction = client.transaction()
try:
snapshot = transaction.read(
table='inventory',
columns=['product_id', 'quantity'],
keys=[product_id]
)
row = list(snapshot)[0]
new_quantity = row[1] + quantity
transaction.update(
table='inventory',
columns=['product_id', 'quantity'],
values=[(product_id, new_quantity)]
)
transaction.commit()
except Exception as e:
transaction.rollback()
raise e
Comparison
| Feature | CockroachDB | TiDB | Spanner |
|---|---|---|---|
| License | Open-source | Open-source | Proprietary |
| Storage | RocksDB | TiKV | Colossus |
| SQL | PostgreSQL | MySQL | PostgreSQL-like |
| Global | Yes | Yes | Yes |
| HTAP | Limited | Yes | Limited |
| Cloud | Self-hosted + DBaaS | Self-hosted + DBaaS | GCP only |
Use Cases
newsql_use_cases:
- "Global e-commerce platforms"
- "Financial transactions needing ACID"
- "Multi-region applications"
- "Real-time analytics + transactions"
- "Replace sharded MySQL/PostgreSQL"
Best Practices
# NewSQL best practices
design:
- "Choose right partition key"
- "Avoid cross-partition transactions"
- "Use serializable isolation carefully"
- "Monitor latencies across regions"
performance:
- "Place replicas near users"
- "Batch operations when possible"
- "Use follower reads for analytics"
Conclusion
NewSQL provides:
- ACID: Strong consistency guarantees
- Scaling: Horizontal scaling across regions
- SQL: Familiar query interface
Choose based on deployment preference: self-managed (CockroachDB, TiDB) or managed (Spanner).
Comments