| name | performance-optimization |
| description | Profiling, optimization techniques, and performance best practices |
| domain | software-engineering |
| version | 1.0.0 |
| tags | ["performance","profiling","optimization","caching","database","frontend"] |
| triggers | {"keywords":{"primary":["performance","optimize","optimization","profiling","benchmark","speed"],"secondary":["caching","latency","throughput","memory","cpu","bottleneck","lighthouse"]},"context_boost":["slow","fast","improve","scale"],"context_penalty":["design","architecture","security"],"priority":"high"} |
Performance Optimization
Overview
Measure first, optimize second. This guide covers profiling techniques and optimization strategies.
Profiling First
The Golden Rule
1. Don't optimize prematurely
2. Measure before optimizing
3. Optimize the biggest bottleneck first
4. Measure again to verify improvement
CPU Profiling (Node.js)
import { performance, PerformanceObserver } from 'perf_hooks';
const obs = new PerformanceObserver((items) => {
items.getEntries().forEach((entry) => {
console.log(`${entry.name}: ${entry.duration}ms`);
});
});
obs.observe({ entryTypes: ['measure'] });
performance.mark('start');
await expensiveOperation();
performance.mark('end');
performance.measure('expensive-op', 'start', 'end');
Memory Profiling
console.log(process.memoryUsage());
const v8 = require('v8');
const fs = require('fs');
const snapshotFile = `heap-${Date.now()}.heapsnapshot`;
const snapshot = v8.writeHeapSnapshot(snapshotFile);
Database Optimization
Query Optimization
SELECT * FROM orders WHERE user_id = 123;
CREATE INDEX idx_orders_user_id ON orders(user_id);
SELECT id, total, status FROM orders WHERE user_id = 123;
SELECT * FROM users;
SELECT * FROM orders WHERE user_id = 1;
SELECT * FROM orders WHERE user_id = 2;
...
SELECT u.*, o.* FROM users u
LEFT JOIN orders o ON u.id = o.user_id;
SELECT * FROM orders WHERE user_id IN (1, 2, 3, ...);
Explain Analyze
EXPLAIN ANALYZE
SELECT u.name, COUNT(o.id) as order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.created_at > '2024-01-01'
GROUP BY u.id
ORDER BY order_count DESC
LIMIT 10;
Index Strategies
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_orders_status_created ON orders(status, created_at);
CREATE INDEX idx_active_users ON users(email)
WHERE status = 'active';
CREATE INDEX idx_orders_user_covering ON orders(user_id)
INCLUDE (total, status, created_at);
Caching
Cache Strategies
async function getUser(id: string): Promise<User> {
const cached = await cache.get(`user:${id}`);
if (cached) return JSON.parse(cached);
const user = await db.users.findById(id);
if (user) {
await cache.set(`user:${id}`, JSON.stringify(user), 'EX', 3600);
}
return user;
}
async function updateUser(id: string, data: Partial<User>): Promise<User> {
const user = await db.users.update(id, data);
cache.(, .(user), , );
user;
}
Cache Invalidation
eventBus.on('user:updated', async (userId: string) => {
await cache.del(`user:${userId}`);
await cache.del(`user:${userId}:orders`);
});
async function invalidateUserRelated(userId: string) {
const keys = await cache.keys(`*:user:${userId}:*`);
if (keys.length > 0) {
await cache.del(...keys);
}
}
const CACHE_VERSION = 'v2';
const cacheKey = `${CACHE_VERSION}:user:${id}`;
Memoization
function memoize<T extends (...args: any[]) => any>(fn: T): T {
const cache = new Map();
return ((...args: Parameters<T>) => {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key);
const result = fn(...args);
cache.set(key, result);
return result;
}) as T;
}
function memoizeWithTTL<T extends (...args: any[]) => any>(
fn: T,
ttlMs: number
): T {
const cache = new Map<string, { value: any; expires: number }>();
return ((...args: Parameters<T>) => {
const key = JSON.stringify(args);
cached = cache.(key);
(cached && cached. > .()) {
cached.;
}
result = (...args);
cache.(key, { : result, : .() + ttlMs });
result;
}) T;
}
Frontend Performance
Core Web Vitals
| Metric | Good | Description |
|---|
| LCP | < 2.5s | Largest Contentful Paint |
| INP | < 200ms | Interaction to Next Paint |
| CLS | < 0.1 | Cumulative Layout Shift |
Code Splitting
import { lazy, Suspense } from 'react';
const Dashboard = lazy(() => import('./Dashboard'));
const Settings = lazy(() => import('./Settings'));
function App() {
return (
<Suspense fallback={<Loading />}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Suspense>
);
}
async function processImage(file: File) {
const sharp = await import('sharp');
(file).().();
}
Image Optimization
<img
src="image-800.jpg"
srcset="
image-400.jpg 400w,
image-800.jpg 800w,
image-1200.jpg 1200w
"
sizes="(max-width: 600px) 400px, 800px"
loading="lazy"
alt="Description"
/>
<picture>
<source srcset="image.avif" type="image/avif" />
<source srcset="image.webp" type="image/webp" />
<img src="image.jpg" alt="Description" />
</picture>
Bundle Optimization
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
react: {
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
name: 'react',
chunks: 'all',
},
},
},
},
};
Backend Performance
Connection Pooling
import { Pool } from 'pg';
const pool = new Pool({
max: 20,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000,
});
async function getUser(id: string) {
const result = await pool.query('SELECT * FROM users WHERE id = $1', [id]);
return result.rows[0];
}
import http from 'http';
const agent = new http.Agent({
keepAlive: true,
maxSockets: 50,
});
fetch('https://api.example.com', { agent });
Async Processing
app.post('/api/orders', async (req, res) => {
const order = await db.orders.create(req.body);
await queue.add('send-confirmation-email', { orderId: order.id });
await queue.add('update-inventory', { items: order.items });
await queue.add('notify-warehouse', { orderId: order.id });
res.status(201).json(order);
});
queue.process('send-confirmation-email', async (job) => {
const order = await db.orders.findById(job.data.orderId);
await emailService.sendOrderConfirmation(order);
});
Response Compression
import compression from 'compression';
import express from 'express';
const app = express();
app.use(compression({
threshold: 1024,
filter: (req, res) => {
if (req.headers['x-no-compression']) {
return false;
}
return compression.filter(req, res);
}
}));
Algorithm Optimization
Time Complexity
function hasDuplicates(arr: number[]): boolean {
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (arr[i] === arr[j]) return true;
}
}
return false;
const seen = new Set<number>();
for (const num of arr) {
if (seen.has(num)) return true;
seen.add(num);
}
return false;
}
class UserCache {
private users: User[] = [];
find(id: string) {
return this.users.find( u. === id);
}
usersMap = <, >();
() {
..(id);
}
}
Space vs Time Tradeoff
class TaxCalculator {
private taxRates = new Map<string, number>();
constructor() {
for (const state of US_STATES) {
this.taxRates.set(state, this.computeTaxRate(state));
}
}
getTaxRate(state: string): number {
return this.taxRates.get(state) ?? 0;
}
}
Monitoring Performance
import { Counter, Histogram } from 'prom-client';
const httpRequestDuration = new Histogram({
name: 'http_request_duration_seconds',
help: 'Duration of HTTP requests',
labelNames: ['method', 'route', 'status'],
buckets: [0.1, 0.5, 1, 2, 5]
});
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = (Date.now() - start) / 1000;
httpRequestDuration
.labels(req.method, req.route?.path || 'unknown', res.statusCode.toString())
.observe(duration);
});
next();
});
Related Skills
- [[database]] - Database optimization details
- [[frontend]] - Frontend performance
- [[monitoring-observability]] - Performance monitoring