As a best-selling author, I invite you to explore my books on Amazon. Don't forget to follow me on Medium and show your support. Thank you! Your support means the world!
I've spent years refining database interactions in Python applications. Performance bottlenecks often hide in data access layers, especially as applications scale. Let me share practical techniques that significantly improve ORM efficiency without sacrificing productivity.
Database connections are expensive to establish. Pooling maintains active connections for reuse. I configure pools based on traffic patterns:
from sqlalchemy import create_engine
from sqlalchemy.pool import NullPool, QueuePool
# Development configuration
dev_engine = create_engine(
"sqlite:///dev.db",
poolclass=NullPool # Disables pooling for simplicity
)
# Production PostgreSQL configuration
prod_engine = create_engine(
"postgresql://prod_user:securepass@cluster.prod/db",
poolclass=QueuePool,
pool_size=15, # Optimal for our typical load
max_overflow=8, # Temporary connections during spikes
pool_timeout=5, # Fail fast during high contention
pool_recycle=300 # Recycle connections every 5 minutes
)
Bulk operations transform database performance. Instead of individual inserts, batch them. This reduced our data import times by 92%:
from sqlalchemy.orm import Session
import time
def efficient_bulk_insert(records, batch_size=1000):
session = Session(engine)
total_records = len(records)
start = time.perf_counter()
for i in range(0, total_records, batch_size):
batch = records[i:i+batch_size]
session.bulk_save_objects(batch)
session.commit() # Single transaction per batch
print(f"Inserted {min(i+batch_size, total_records)}/{total_records}")
duration = time.perf_counter() - start
print(f"Inserted {total_records} records in {duration:.2f}s")
Indexes accelerate queries when properly designed. Covering indexes avoid table lookups entirely. Here's how I optimize frequent lookups:
# Create covering index for email lookups
Index('user_email_cover', User.email, postgresql_include=['id', 'last_login'])
# Optimized query using index-only scan
active_users = session.query(User.id, User.last_login).filter(
User.email.ilike('%@company.com'),
User.last_login > datetime.now() - timedelta(days=30)
).all()
Materialized views precompute complex aggregations. I use them for dashboard metrics that update hourly:
# Create scheduled view refresh
with engine.connect() as conn:
conn.execute(text("""
CREATE MATERIALIZED VIEW sales_summary AS
SELECT product_id,
SUM(quantity) AS total_sold,
AVG(unit_price) AS avg_price
FROM orders
GROUP BY product_id
"""))
# Refresh via cron job
def refresh_materialized_views():
with engine.begin() as conn:
conn.execute(text("REFRESH MATERIALIZED VIEW CONCURRENTLY sales_summary"))
print("Views refreshed at", datetime.utcnow())
Partial loading minimizes data transfer. Fetch only necessary columns:
# Fetch minimal data for list display
customers = session.query(Customer).options(
load_only(Customer.name, Customer.membership_level, Customer.last_purchase_date)
).filter(Customer.is_active == True).limit(100).all()
Caching frequent queries with Redis eliminates database hits. My decorator handles cache population and invalidation:
import redis
from functools import wraps
r = redis.Redis(host='cache.prod', port=6379, db=0)
def cache_query(cache_key, expire=600):
def decorator(query_func):
@wraps(query_func)
def wrapper(*args, **kwargs):
serialized_args = pickle.dumps((args, kwargs))
cache_key_full = f"{cache_key}:{hash(serialized_args)}"
if cached := r.get(cache_key_full):
return pickle.loads(cached)
result = query_func(*args, **kwargs)
r.setex(cache_key_full, expire, pickle.dumps(result))
return result
return wrapper
return decorator
@cache_query("user_profile")
def get_user_profile(user_id):
return session.query(User).options(
load_only(User.name, User.avatar_url, User.bio)
).get(user_id)
Read replicas distribute query load. Our router directs traffic based on operation type:
from sqlalchemy.ext.horizontal_shard import ShardedSession
shard_map = {
'primary': create_engine('postgresql://master.prod/db'),
'replica1': create_engine('postgresql://replica1.prod/db?application_name=webapp'),
'replica2': create_engine('postgresql://replica2.prod/db?application_name=webapp')
}
def route_query(mapper, instance, clause=None):
if clause and clause.is_select:
# Distribute reads randomly
return ['replica1', 'replica2'][hash(clause) % 2]
return ['primary'] # Writes to master
sharded_session = ShardedSession(
bind_map=shard_map,
shard_chooser=route_query
)
NoSQL optimizations differ from relational databases. When working with MongoDB, I use atomic updates:
from pymongo import MongoClient
from bson import ObjectId
client = MongoClient('mongodb://nosql.prod:27017')
db = client.app_data
def update_user_preferences(user_id, preferences):
result = db.users.update_one(
{'_id': ObjectId(user_id)},
{'$set': {'preferences': preferences}},
upsert=False
)
if result.modified_count == 0:
raise ValueError("User document not updated")
Each technique requires understanding your specific workload. I measure everything before optimization - you might be surprised where actual bottlenecks hide. Start with connection pooling and selective loading, as they often yield immediate improvements. For batch processes, focus on write batching. Remember that over-indexing can degrade write performance, so monitor index usage regularly. Caching delivers dramatic improvements but adds complexity - implement it where queries repeat frequently with stable results. Materialized views work best for complex aggregations on slowly changing data. The key is balancing these techniques based on your application's unique patterns.
📘 Checkout my latest ebook for free on my channel!
Be sure to like, share, comment, and subscribe to the channel!
101 Books
101 Books is an AI-driven publishing company co-founded by author Aarav Joshi. By leveraging advanced AI technology, we keep our publishing costs incredibly low—some books are priced as low as $4—making quality knowledge accessible to everyone.
Check out our book Golang Clean Code available on Amazon.
Stay tuned for updates and exciting news. When shopping for books, search for Aarav Joshi to find more of our titles. Use the provided link to enjoy special discounts!
Our Creations
Be sure to check out our creations:
Investor Central | Investor Central Spanish | Investor Central German | Smart Living | Epochs & Echoes | Puzzling Mysteries | Hindutva | Elite Dev | Java Elite Dev | Golang Elite Dev | Python Elite Dev | JS Elite Dev | JS Schools
We are on Medium
Tech Koala Insights | Epochs & Echoes World | Investor Central Medium | Puzzling Mysteries Medium | Science & Epochs Medium | Modern Hindutva
Top comments (0)