# Ankit Rana | Mechanical Sympathy

Engineering logs on distributed systems, database internals, CPU and memory behaviour, and AI infrastructure by Ankit Rana, Senior Software Engineer at Walmart Global Tech.

This is one page of public article previews, not the complete archive. Follow Next page to continue. Summaries are not the original full articles.

## Local and distributed cache coherence: stale data caused by missed invalidation messages

DevFeed: [Local and distributed cache coherence: stale data caused by missed invalidation messages](<https://devfeed.tech/articles/local-cache-plus-distributed-cache-the-coherence-bill-nobody-budgets-for-39606.md>)

Original publisher: [Read original article](<https://ankit-rana.com/logs/54-local-and-distributed-cache-coherence/>)

Author: hello@ankit-rana.com

Published: 2026-09-17T00:00:00Z

Content type: opinion

Language: en

Sources: [Ankit Rana | Mechanical Sympathy](<https://devfeed.tech/sources/ankit-rana-mechanical-sympathy.md>)

Topics: [Caching](<https://devfeed.tech/topics/caching.md>), [Redis](<https://devfeed.tech/topics/redis.md>), [data](<https://devfeed.tech/topics/data.md>), [Network](<https://devfeed.tech/topics/network.md>)

Tags: [cache](<https://devfeed.tech/tags/cache.md>), [cache-coherence](<https://devfeed.tech/tags/cache-coherence.md>), [caching](<https://devfeed.tech/tags/caching.md>), [consistency](<https://devfeed.tech/tags/consistency.md>), [data](<https://devfeed.tech/tags/data.md>), [distributed-cache](<https://devfeed.tech/tags/distributed-cache.md>), [distributed-systems](<https://devfeed.tech/tags/distributed-systems.md>), [jvm](<https://devfeed.tech/tags/jvm.md>), [network](<https://devfeed.tech/tags/network.md>), [redis](<https://devfeed.tech/tags/redis.md>), [ttl](<https://devfeed.tech/tags/ttl.md>)

### AI overview

The article explains that adding an in-process cache in front of a distributed cache can improve latency but creates independently stale copies across service instances. It focuses on Redis pub/sub invalidation, which provides no persistence, acknowledgement, retry, or replay, allowing instances to miss invalidation messages and serve stale data until their TTL expires.

### Source excerpt

An in-process cache in front of a distributed cache removes a network hop and adds one independent copy of the data per instance, each of which can be stale on its own schedule. Invalidation is normally broadcast over pub/sub, which is fire and forget, so any instance that is restarting, garbage collecting or briefly disconnected simply misses the message and serves stale data until its TTL expires. That TTL is not a performance setting, it is the maximum duration of incorrectness.

## Why your Redis is slow: it is single threaded and you sent it KEYS

DevFeed: [Why your Redis is slow: it is single threaded and you sent it KEYS](<https://devfeed.tech/articles/why-your-redis-is-slow-it-is-single-threaded-and-you-sent-it-keys-39605.md>)

Original publisher: [Read original article](<https://ankit-rana.com/logs/53-redis-single-threaded-keys-command/>)

Author: hello@ankit-rana.com

Published: 2026-09-15T00:00:00Z

Content type: tutorial

Language: en

Sources: [Ankit Rana | Mechanical Sympathy](<https://devfeed.tech/sources/ankit-rana-mechanical-sympathy.md>)

Topics: [Redis](<https://devfeed.tech/topics/redis.md>), [Latency](<https://devfeed.tech/topics/latency.md>), [Concurrency](<https://devfeed.tech/topics/concurrency.md>)

Tags: [blocking](<https://devfeed.tech/tags/blocking.md>), [caching](<https://devfeed.tech/tags/caching.md>), [command](<https://devfeed.tech/tags/command.md>), [latency](<https://devfeed.tech/tags/latency.md>), [observability](<https://devfeed.tech/tags/observability.md>), [performance](<https://devfeed.tech/tags/performance.md>), [redis](<https://devfeed.tech/tags/redis.md>), [single-threaded](<https://devfeed.tech/tags/single-threaded.md>)

### AI overview

The article explains that Redis executes commands one at a time on a single thread, so expensive commands can block every client and cause latency spikes across all operations. It identifies KEYS as a key offender and also discusses large DEL operations, unbounded LRANGE, SMEMBERS on large sets, and FLUSHALL. Redis 6 threaded I/O helps with socket handling but does not change single-threaded command execution.

### Source excerpt

Redis executes commands one at a time on a single thread, so any command that takes 200ms makes every other client wait 200ms regardless of how trivial their request was. KEYS scans the entire keyspace and is the obvious offender, but DEL on a large collection, unbounded LRANGE, SMEMBERS on a big set and FLUSHALL are all linear in the size of the data and block identically. The tell is a latency spike across all operations at once while CPU and network look normal.

## Cache invalidation is a distributed systems problem

DevFeed: [Cache invalidation is a distributed systems problem](<https://devfeed.tech/articles/cache-invalidation-is-a-distributed-systems-problem-in-a-convenience-costume-39604.md>)

Original publisher: [Read original article](<https://ankit-rana.com/logs/52-cache-invalidation-distributed-problem/>)

Author: hello@ankit-rana.com

Published: 2026-09-13T00:00:00Z

Content type: tutorial

Language: en

Sources: [Ankit Rana | Mechanical Sympathy](<https://devfeed.tech/sources/ankit-rana-mechanical-sympathy.md>)

Topics: [Cache](<https://devfeed.tech/topics/cache.md>), [Caching](<https://devfeed.tech/topics/caching.md>), [distributed-systems](<https://devfeed.tech/topics/distributed-systems.md>)

Tags: [cache](<https://devfeed.tech/tags/cache.md>), [cache-invalidation](<https://devfeed.tech/tags/cache-invalidation.md>), [caching](<https://devfeed.tech/tags/caching.md>), [consistency](<https://devfeed.tech/tags/consistency.md>), [distributed](<https://devfeed.tech/tags/distributed.md>), [distributed-systems](<https://devfeed.tech/tags/distributed-systems.md>), [ordering](<https://devfeed.tech/tags/ordering.md>), [race-conditions](<https://devfeed.tech/tags/race-conditions.md>), [redis](<https://devfeed.tech/tags/redis.md>), [ttl](<https://devfeed.tech/tags/ttl.md>)

### AI overview

Cache invalidation coordinates updates between a database and a cache without a shared transaction. The article explains how operation ordering can let a concurrent reader repopulate stale data and recommends writing to the database before invalidating the cache, followed by a second invalidation to close the remaining race.

### Source excerpt

A cache and a database are two stores that must agree, which makes every invalidation a distributed transaction without a coordinator. The ordering matters more than the mechanism: invalidating before the database write leaves a window where a concurrent reader repopulates the cache with the old value and it stays wrong until the TTL expires. Deleting the key rather than writing the new value removes a whole class of ordering bug, because two concurrent deletes commute and two concurrent writes do not.

## Choosing among write-through, write-behind, and write-around caching strategies

DevFeed: [Choosing among write-through, write-behind, and write-around caching strategies](<https://devfeed.tech/articles/write-through-write-behind-write-around-picking-wrong-costs-you-consistency-or-throughput-39603.md>)

Original publisher: [Read original article](<https://ankit-rana.com/logs/51-write-through-behind-around/>)

Author: hello@ankit-rana.com

Published: 2026-09-11T00:00:00Z

Content type: tutorial

Language: en

Sources: [Ankit Rana | Mechanical Sympathy](<https://devfeed.tech/sources/ankit-rana-mechanical-sympathy.md>)

Topics: [Caching](<https://devfeed.tech/topics/caching.md>), [Databases](<https://devfeed.tech/topics/databases.md>), [Redis](<https://devfeed.tech/topics/redis.md>), [consistency](<https://devfeed.tech/topics/consistency.md>), [Latency](<https://devfeed.tech/topics/latency.md>)

Tags: [cache](<https://devfeed.tech/tags/cache.md>), [caching](<https://devfeed.tech/tags/caching.md>), [consistency](<https://devfeed.tech/tags/consistency.md>), [database](<https://devfeed.tech/tags/database.md>), [latency](<https://devfeed.tech/tags/latency.md>), [orders](<https://devfeed.tech/tags/orders.md>), [postgres](<https://devfeed.tech/tags/postgres.md>), [redis](<https://devfeed.tech/tags/redis.md>), [strategies](<https://devfeed.tech/tags/strategies.md>), [system-design](<https://devfeed.tech/tags/system-design.md>), [write](<https://devfeed.tech/tags/write.md>), [write-behind](<https://devfeed.tech/tags/write-behind.md>), [write-through](<https://devfeed.tech/tags/write-through.md>)

### AI overview

This article compares write-through, write-behind, and write-around caching strategies. It explains their trade-offs among database latency, cache hit rates, consistency, and the risk of losing acknowledged writes when a process fails.

### Source excerpt

The three write strategies differ in what happens between the cache write and the database write, and that gap is where correctness lives. Write-through updates both before acknowledging, so it is safe and pays the full database latency. Write-behind acknowledges after the cache write and flushes later, which is fast and can lose acknowledged writes if the process dies. Write-around skips the cache entirely on write, which avoids caching data nobody reads and costs a miss on the next read.

## Negative caching protects databases from repeated lookups for nonexistent keys

DevFeed: [Negative caching protects databases from repeated lookups for nonexistent keys](<https://devfeed.tech/articles/negative-caching-the-misses-cost-more-than-the-hits-39602.md>)

Original publisher: [Read original article](<https://ankit-rana.com/logs/50-negative-caching-misses-cost-more/>)

Author: hello@ankit-rana.com

Published: 2026-09-09T00:00:00Z

Content type: tutorial

Language: en

Sources: [Ankit Rana | Mechanical Sympathy](<https://devfeed.tech/sources/ankit-rana-mechanical-sympathy.md>)

Topics: [Caching](<https://devfeed.tech/topics/caching.md>), [Cache](<https://devfeed.tech/topics/cache.md>), [Database](<https://devfeed.tech/topics/database.md>), [Security](<https://devfeed.tech/topics/security.md>), [Latency](<https://devfeed.tech/topics/latency.md>)

Tags: [cache](<https://devfeed.tech/tags/cache.md>), [cache-penetration](<https://devfeed.tech/tags/cache-penetration.md>), [caching](<https://devfeed.tech/tags/caching.md>), [database](<https://devfeed.tech/tags/database.md>), [negative-caching](<https://devfeed.tech/tags/negative-caching.md>), [protection](<https://devfeed.tech/tags/protection.md>), [redis](<https://devfeed.tech/tags/redis.md>), [reliability](<https://devfeed.tech/tags/reliability.md>), [security](<https://devfeed.tech/tags/security.md>), [ttl](<https://devfeed.tech/tags/ttl.md>)

### AI overview

Negative caching prevents repeated database queries for nonexistent keys by storing a distinguishable marker for negative results. The article explains how partner integrations, scrapers, stale clients, migrations, or attackers can exploit this gap and recommends using a shorter TTL for negative entries.

### Source excerpt

A cache that stores only found values gives you no protection against lookups for things that do not exist, and a miss on a nonexistent key costs the full origin query every single time. If the key is user supplied, an attacker can generate unlimited unique misses and bypass the cache entirely, which is cache penetration. Caching the negative result fixes it, with a shorter TTL than positive entries because a value appearing is a much more likely event than one disappearing.

## How Fixed Intervals Synchronize Distributed Clients and How Jitter Helps

DevFeed: [How Fixed Intervals Synchronize Distributed Clients and How Jitter Helps](<https://devfeed.tech/articles/jitter-is-the-cheapest-reliability-fix-you-are-not-using-39601.md>)

Original publisher: [Read original article](<https://ankit-rana.com/logs/49-jitter-synchronised-clients/>)

Author: hello@ankit-rana.com

Published: 2026-09-07T00:00:00Z

Content type: opinion

Language: en

Sources: [Ankit Rana | Mechanical Sympathy](<https://devfeed.tech/sources/ankit-rana-mechanical-sympathy.md>)

Topics: [reliability](<https://devfeed.tech/topics/reliability.md>), [distributed-systems](<https://devfeed.tech/topics/distributed-systems.md>), [systems](<https://devfeed.tech/topics/systems.md>), [Network](<https://devfeed.tech/topics/network.md>), [Cache](<https://devfeed.tech/topics/cache.md>), [Redis](<https://devfeed.tech/topics/redis.md>)

Tags: [aws](<https://devfeed.tech/tags/aws.md>), [cache](<https://devfeed.tech/tags/cache.md>), [code](<https://devfeed.tech/tags/code.md>), [distributed-systems](<https://devfeed.tech/tags/distributed-systems.md>), [jitter](<https://devfeed.tech/tags/jitter.md>), [network](<https://devfeed.tech/tags/network.md>), [reliability](<https://devfeed.tech/tags/reliability.md>), [resilience](<https://devfeed.tech/tags/resilience.md>), [retries](<https://devfeed.tech/tags/retries.md>), [thundering-herd](<https://devfeed.tech/tags/thundering-herd.md>)

### AI overview

Fixed retry intervals, TTLs, restarts, reconnects, and other recurring events can cause independent clients in distributed systems to synchronize, producing repeated load spikes. Adding randomness, or jitter, helps break that alignment; the article cites AWS measurements indicating that full jitter improves total work and completion time under contention.

### Source excerpt

Distributed systems synchronise themselves without being told to: every client that retries on a fixed interval, restarts after a deploy, or reconnects after a network blip ends up firing at the same moment as every other client. The resulting spike is a self-inflicted denial of service that no single component is responsible for. Adding randomness to any repeating interval breaks the alignment, and it is usually one line of code against a failure mode that otherwise requires capacity you never needed.

## Cache stampede: how one expired key takes down the database

DevFeed: [Cache stampede: how one expired key takes down the database](<https://devfeed.tech/articles/cache-stampede-how-one-expired-key-takes-down-the-database-39600.md>)

Original publisher: [Read original article](<https://ankit-rana.com/logs/48-cache-stampede-expired-key/>)

Author: hello@ankit-rana.com

Published: 2026-09-05T00:00:00Z

Content type: tutorial

Language: en

Sources: [Ankit Rana | Mechanical Sympathy](<https://devfeed.tech/sources/ankit-rana-mechanical-sympathy.md>)

Topics: [Cache](<https://devfeed.tech/topics/cache.md>), [Caching](<https://devfeed.tech/topics/caching.md>), [Database](<https://devfeed.tech/topics/database.md>), [consistent hashing](<https://devfeed.tech/topics/consistent-hashing.md>), [Redis](<https://devfeed.tech/topics/redis.md>)

Tags: [cache-stampede](<https://devfeed.tech/tags/cache-stampede.md>), [caching](<https://devfeed.tech/tags/caching.md>), [connection-pool](<https://devfeed.tech/tags/connection-pool.md>), [consistent-hashing](<https://devfeed.tech/tags/consistent-hashing.md>), [distributed-systems](<https://devfeed.tech/tags/distributed-systems.md>), [jitter](<https://devfeed.tech/tags/jitter.md>), [query](<https://devfeed.tech/tags/query.md>), [redis](<https://devfeed.tech/tags/redis.md>), [reliability](<https://devfeed.tech/tags/reliability.md>), [thundering-herd](<https://devfeed.tech/tags/thundering-herd.md>), [traffic](<https://devfeed.tech/tags/traffic.md>), [ttl](<https://devfeed.tech/tags/ttl.md>)

### AI overview

This article explains how a cache stampede occurs when a hot key expires and many requests simultaneously recompute the same value against the database. It recommends TTL jitter to prevent synchronized expirations and request coalescing so only one caller recomputes while others wait or serve stale data. It also discusses cache warming and consistent hashing for broader cache-failure scenarios.

### Source excerpt

A cache TTL is a scheduled simultaneous failure: every request being served from one key misses at the same instant and goes to the origin together. If the recompute takes two seconds, every request arriving during those two seconds also misses, so the pileup grows faster than it drains. Jitter on the TTL stops keys expiring in lockstep, and request coalescing so only one caller recomputes while the rest wait or serve stale is what stops a single expensive key from saturating the database.

## JDBC batching can still issue one round trip per row unless driver statement rewriting is enabled

DevFeed: [JDBC batching can still issue one round trip per row unless driver statement rewriting is enabled](<https://devfeed.tech/articles/one-round-trip-beats-a-thousand-and-your-batch-api-probably-is-not-batching-39599.md>)

Original publisher: [Read original article](<https://ankit-rana.com/logs/47-batching-one-round-trip-beats-a-thousand/>)

Author: hello@ankit-rana.com

Published: 2026-09-03T00:00:00Z

Content type: tutorial

Language: en

Sources: [Ankit Rana | Mechanical Sympathy](<https://devfeed.tech/sources/ankit-rana-mechanical-sympathy.md>)

Topics: [Databases](<https://devfeed.tech/topics/databases.md>), [Latency](<https://devfeed.tech/topics/latency.md>), [client](<https://devfeed.tech/topics/client.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [batching](<https://devfeed.tech/tags/batching.md>), [bulk-load](<https://devfeed.tech/tags/bulk-load.md>), [client](<https://devfeed.tech/tags/client.md>), [cost](<https://devfeed.tech/tags/cost.md>), [database](<https://devfeed.tech/tags/database.md>), [database-performance](<https://devfeed.tech/tags/database-performance.md>), [durability](<https://devfeed.tech/tags/durability.md>), [jdbc](<https://devfeed.tech/tags/jdbc.md>), [latency](<https://devfeed.tech/tags/latency.md>), [mysql](<https://devfeed.tech/tags/mysql.md>), [postgresql](<https://devfeed.tech/tags/postgresql.md>), [server](<https://devfeed.tech/tags/server.md>), [sql](<https://devfeed.tech/tags/sql.md>)

### AI overview

For small database writes, network round trips and transaction overhead can dominate the actual insert work. The article explains that JDBC batching may accept rows into a client-side batch while still sending separate statements unless driver-side statement rewriting is enabled, and that autocommit adds a transaction and durability barrier per row.

### Source excerpt

For small writes the per-statement overhead dominates the actual work, so throughput is set by round trips rather than by the database. JDBC batching is the usual fix and it silently does nothing on the wire unless the driver is told to rewrite the statements, so addBatch can look correct while still issuing one round trip per row. Autocommit compounds it by turning every row into its own transaction and its own durability barrier, which is the difference between one fsync and a hundred thousand.

## When JSONB columns create schema, consistency, and performance problems

DevFeed: [When JSONB columns create schema, consistency, and performance problems](<https://devfeed.tech/articles/your-jsonb-column-became-the-schemaless-disaster-you-migrated-away-from-39598.md>)

Original publisher: [Read original article](<https://ankit-rana.com/logs/46-jsonb-column-schemaless-disaster/>)

Author: hello@ankit-rana.com

Published: 2026-09-01T00:00:00Z

Content type: article

Language: en

Sources: [Ankit Rana | Mechanical Sympathy](<https://devfeed.tech/sources/ankit-rana-mechanical-sympathy.md>)

Topics: [data](<https://devfeed.tech/topics/data.md>), [Structured-data](<https://devfeed.tech/topics/structured-data.md>), [JSON](<https://devfeed.tech/topics/json.md>)

Tags: [data-modelling](<https://devfeed.tech/tags/data-modelling.md>), [indexing](<https://devfeed.tech/tags/indexing.md>), [jsonb](<https://devfeed.tech/tags/jsonb.md>), [migration](<https://devfeed.tech/tags/migration.md>), [outage](<https://devfeed.tech/tags/outage.md>), [postgres](<https://devfeed.tech/tags/postgres.md>), [postgresql](<https://devfeed.tech/tags/postgresql.md>), [query](<https://devfeed.tech/tags/query.md>), [schema](<https://devfeed.tech/tags/schema.md>), [schema-design](<https://devfeed.tech/tags/schema-design.md>), [toast](<https://devfeed.tech/tags/toast.md>)

### AI overview

The article explains why using JSONB to avoid recurring migrations can create hidden schema and data-consistency problems. It discusses runtime failures from inconsistent keys and types, difficulty identifying dependencies across consumers, and the storage and update costs of large PostgreSQL JSONB documents.

### Source excerpt

JSONB is a good fit for genuinely open-ended data and a poor one for schema you did not want to commit to yet. Without a schema there is no NOT NULL, no type, no foreign key and no way to know which keys are load bearing, so every read becomes a parse and a cast that can fail at runtime. Large documents are stored out of line and compressed, which means reading one key can require fetching and decompressing the whole document, and updating one key rewrites all of it.

## Foreign keys are not overhead, and the thing you measured was a missing index

DevFeed: [Foreign keys are not overhead, and the thing you measured was a missing index](<https://devfeed.tech/articles/foreign-keys-are-not-overhead-and-the-thing-you-measured-was-a-missing-index-39597.md>)

Original publisher: [Read original article](<https://ankit-rana.com/logs/45-foreign-keys-are-not-overhead/>)

Author: hello@ankit-rana.com

Published: 2026-08-30T00:00:00Z

Content type: opinion

Language: en

Sources: [Ankit Rana | Mechanical Sympathy](<https://devfeed.tech/sources/ankit-rana-mechanical-sympathy.md>)

Topics: [Database](<https://devfeed.tech/topics/database.md>), [integrity](<https://devfeed.tech/topics/integrity.md>)

Tags: [database](<https://devfeed.tech/tags/database.md>), [database-performance](<https://devfeed.tech/tags/database-performance.md>), [foreign-keys](<https://devfeed.tech/tags/foreign-keys.md>), [indexing](<https://devfeed.tech/tags/indexing.md>), [integrity](<https://devfeed.tech/tags/integrity.md>), [overhead](<https://devfeed.tech/tags/overhead.md>), [postgres](<https://devfeed.tech/tags/postgres.md>), [postgresql](<https://devfeed.tech/tags/postgresql.md>), [referential-integrity](<https://devfeed.tech/tags/referential-integrity.md>), [schema-design](<https://devfeed.tech/tags/schema-design.md>)

### AI overview

The article explains that the measured cost of a slow parent delete is usually caused by a missing index on the child table's foreign-key column, not by foreign-key checking itself. It argues that dropping the constraint merely moves referential-integrity enforcement into application code and can allow orphaned records.

### Source excerpt

A foreign key check is an index lookup against a primary key that is almost certainly already in cache, which is close to the cheapest thing a database does. The expensive case people measure is a parent delete with no index on the child's referencing column, which forces a full scan of the child table per deleted row, and that is a missing index rather than a cost of the constraint. Dropping the key does not remove the work, it moves the integrity guarantee into application code where nothing reports when it stops holding.

## Detecting Replica Lag That Breaks Read-Your-Writes Consistency

DevFeed: [Detecting Replica Lag That Breaks Read-Your-Writes Consistency](<https://devfeed.tech/articles/the-replica-lag-you-do-not-measure-is-the-one-serving-checkout-39596.md>)

Original publisher: [Read original article](<https://ankit-rana.com/logs/44-replica-lag-read-your-writes/>)

Author: hello@ankit-rana.com

Published: 2026-08-28T00:00:00Z

Content type: tutorial

Language: en

Sources: [Ankit Rana | Mechanical Sympathy](<https://devfeed.tech/sources/ankit-rana-mechanical-sympathy.md>)

Topics: [Replication](<https://devfeed.tech/topics/replication.md>), [Routing (disambiguation)](<https://devfeed.tech/topics/routing.md>)

Tags: [checkout](<https://devfeed.tech/tags/checkout.md>), [consistency](<https://devfeed.tech/tags/consistency.md>), [lag](<https://devfeed.tech/tags/lag.md>), [metric](<https://devfeed.tech/tags/metric.md>), [observability](<https://devfeed.tech/tags/observability.md>), [postgresql](<https://devfeed.tech/tags/postgresql.md>), [primary](<https://devfeed.tech/tags/primary.md>), [read-replica](<https://devfeed.tech/tags/read-replica.md>), [read-replicas](<https://devfeed.tech/tags/read-replicas.md>), [replica-lag](<https://devfeed.tech/tags/replica-lag.md>), [replication](<https://devfeed.tech/tags/replication.md>), [routing](<https://devfeed.tech/tags/routing.md>)

### AI overview

This article explains how read replicas can break read-your-writes behavior when applications do not route related reads to the primary or wait for replication. It compares byte lag with time lag, explains why idle systems can hide failures, and discusses replay delays caused by write bursts and long-running replica queries.

### Source excerpt

Byte lag between primary and replica reads zero on an idle primary even when replication is completely stuck, so the metric that looks healthiest is the one that hides the failure. Time lag measured from the last replayed transaction is the signal that stays honest. Adding a read replica silently removes read-your-writes, which means any flow that writes and then reads back needs either primary routing or an explicit wait for the replica to reach that write's log position.

## ADD COLUMN is not always free, and the lock queue is what takes you down

DevFeed: [ADD COLUMN is not always free, and the lock queue is what takes you down](<https://devfeed.tech/articles/add-column-is-not-always-free-and-the-lock-queue-is-what-takes-you-down-39595.md>)

Original publisher: [Read original article](<https://ankit-rana.com/logs/43-add-column-is-not-always-free/>)

Author: hello@ankit-rana.com

Published: 2026-08-26T00:00:00Z

Content type: article

Language: en

Sources: [Ankit Rana | Mechanical Sympathy](<https://devfeed.tech/sources/ankit-rana-mechanical-sympathy.md>)

Topics: [PostgreSQL](<https://devfeed.tech/topics/postgresql.md>), [incident](<https://devfeed.tech/topics/incident.md>), [Query (disambiguation)](<https://devfeed.tech/topics/query.md>), [migration](<https://devfeed.tech/topics/migration.md>), [MySQL](<https://devfeed.tech/topics/mysql.md>)

Tags: [ddl](<https://devfeed.tech/tags/ddl.md>), [incident](<https://devfeed.tech/tags/incident.md>), [locking](<https://devfeed.tech/tags/locking.md>), [migration](<https://devfeed.tech/tags/migration.md>), [migrations](<https://devfeed.tech/tags/migrations.md>), [mysql](<https://devfeed.tech/tags/mysql.md>), [postgresql](<https://devfeed.tech/tags/postgresql.md>), [query](<https://devfeed.tech/tags/query.md>), [queues](<https://devfeed.tech/tags/queues.md>), [schema-design](<https://devfeed.tech/tags/schema-design.md>), [timeout](<https://devfeed.tech/tags/timeout.md>)

### AI overview

Adding a nullable column can cause an outage even when the schema change itself is nearly instantaneous. In PostgreSQL, ALTER TABLE may wait for a long-running query, and subsequent queries can queue behind the waiting lock request. Setting a short lock_timeout and retrying can prevent the migration from taking down the table.

### Source excerpt

Modern PostgreSQL adds a column with a default as a metadata change, so the table is never rewritten and the migration itself is instant. The outage comes from lock acquisition instead: ALTER TABLE needs an ACCESS EXCLUSIVE lock, and while it waits behind one long-running query, every subsequent query queues behind the waiting ALTER because the lock queue is ordered. Setting lock_timeout to a couple of seconds and retrying converts that from an outage into a no-op.

## Connection pool sizing is a queueing theory problem, not a tuning knob

DevFeed: [Connection pool sizing is a queueing theory problem, not a tuning knob](<https://devfeed.tech/articles/connection-pool-sizing-is-a-queueing-theory-problem-not-a-tuning-knob-39593.md>)

Original publisher: [Read original article](<https://ankit-rana.com/logs/41-connection-pool-sizing-queueing-theory/>)

Author: hello@ankit-rana.com

Published: 2026-08-22T00:00:00Z

Content type: article

Language: en

Sources: [Ankit Rana | Mechanical Sympathy](<https://devfeed.tech/sources/ankit-rana-mechanical-sympathy.md>)

Topics: [connection pool](<https://devfeed.tech/topics/connection-pool.md>), [queueing theory](<https://devfeed.tech/topics/queueing-theory.md>), [Latency](<https://devfeed.tech/topics/latency.md>), [Database](<https://devfeed.tech/topics/database.md>), [Concurrency](<https://devfeed.tech/topics/concurrency.md>)

Tags: [capacity-planning](<https://devfeed.tech/tags/capacity-planning.md>), [concurrency](<https://devfeed.tech/tags/concurrency.md>), [connection-pool](<https://devfeed.tech/tags/connection-pool.md>), [cpu](<https://devfeed.tech/tags/cpu.md>), [database](<https://devfeed.tech/tags/database.md>), [database-performance](<https://devfeed.tech/tags/database-performance.md>), [hikaricp](<https://devfeed.tech/tags/hikaricp.md>), [inference](<https://devfeed.tech/tags/inference.md>), [latency](<https://devfeed.tech/tags/latency.md>), [network](<https://devfeed.tech/tags/network.md>), [postgresql](<https://devfeed.tech/tags/postgresql.md>), [query](<https://devfeed.tech/tags/query.md>), [queueing-theory](<https://devfeed.tech/tags/queueing-theory.md>)

### AI overview

This article explains how to size a connection pool using Little's law: concurrency equals throughput multiplied by connection holding time. It argues that increasing the pool beyond the database's parallel execution capacity can move the queue, increase latency, and leave throughput flat. It also identifies excessive holding time from network round trips, N+1 queries, long transactions, and model inference calls as common causes of pool exhaustion.

### Source excerpt

Pool size follows from Little's law: concurrency equals throughput multiplied by holding time, so 500 requests per second each holding a connection for 20ms needs ten connections rather than a round number someone picked. Past the point where the database can execute requests in parallel, adding connections moves the queue rather than removing it, and latency grows while throughput stays flat. The number that actually reaches the database is the pool size multiplied by the instance count, which is usually the number nobody has calculated.

## Soft deletes affect database constraints, indexes, and application queries

DevFeed: [Soft deletes affect database constraints, indexes, and application queries](<https://devfeed.tech/articles/soft-deletes-are-a-schema-decision-that-breaks-every-query-you-write-afterwards-39592.md>)

Original publisher: [Read original article](<https://ankit-rana.com/logs/40-soft-deletes-schema-decision/>)

Author: hello@ankit-rana.com

Published: 2026-08-20T00:00:00Z

Content type: opinion

Language: en

Sources: [Ankit Rana | Mechanical Sympathy](<https://devfeed.tech/sources/ankit-rana-mechanical-sympathy.md>)

Topics: [data-processing](<https://devfeed.tech/topics/data-processing.md>), [Database](<https://devfeed.tech/topics/database.md>), [MySQL](<https://devfeed.tech/topics/mysql.md>)

Tags: [data-modelling](<https://devfeed.tech/tags/data-modelling.md>), [database-design](<https://devfeed.tech/tags/database-design.md>), [foreign-keys](<https://devfeed.tech/tags/foreign-keys.md>), [indexes](<https://devfeed.tech/tags/indexes.md>), [indexing](<https://devfeed.tech/tags/indexing.md>), [mysql](<https://devfeed.tech/tags/mysql.md>), [orm](<https://devfeed.tech/tags/orm.md>), [postgresql](<https://devfeed.tech/tags/postgresql.md>), [predicate](<https://devfeed.tech/tags/predicate.md>), [schema](<https://devfeed.tech/tags/schema.md>), [schema-design](<https://devfeed.tech/tags/schema-design.md>), [soft-delete](<https://devfeed.tech/tags/soft-delete.md>)

### AI overview

The article explains how soft deletion affects database design beyond adding a deleted_at column. It discusses duplicate-key failures, foreign-key behavior, queries that may return deleted rows, and index inefficiency, noting that PostgreSQL partial indexes help while MySQL requires a workaround.

### Source excerpt

A deleted_at column turns every future query into a conditional one, and the cost is not the extra predicate. Unique constraints stop working because the deleted row still occupies the key, foreign keys start pointing at rows the application considers gone, and any query written by someone who does not know about the column silently returns deleted data. Soft delete is a data lifecycle decision, and treating it as a boolean column is what makes it expensive.

## Covering Indexes and Index-Only Scans in PostgreSQL

DevFeed: [Covering Indexes and Index-Only Scans in PostgreSQL](<https://devfeed.tech/articles/covering-indexes-the-cheap-10x-that-most-schemas-leave-on-the-table-39591.md>)

Original publisher: [Read original article](<https://ankit-rana.com/logs/39-covering-indexes-index-only-scans/>)

Author: hello@ankit-rana.com

Published: 2026-08-18T00:00:00Z

Content type: tutorial

Language: en

Sources: [Ankit Rana | Mechanical Sympathy](<https://devfeed.tech/sources/ankit-rana-mechanical-sympathy.md>)

Topics: [PostgreSQL](<https://devfeed.tech/topics/postgresql.md>), [Query (disambiguation)](<https://devfeed.tech/topics/query.md>), [data](<https://devfeed.tech/topics/data.md>)

Tags: [b-tree](<https://devfeed.tech/tags/b-tree.md>), [cache](<https://devfeed.tech/tags/cache.md>), [covering](<https://devfeed.tech/tags/covering.md>), [covering-index](<https://devfeed.tech/tags/covering-index.md>), [database-performance](<https://devfeed.tech/tags/database-performance.md>), [explain](<https://devfeed.tech/tags/explain.md>), [heap](<https://devfeed.tech/tags/heap.md>), [indexes](<https://devfeed.tech/tags/indexes.md>), [indexing](<https://devfeed.tech/tags/indexing.md>), [innodb](<https://devfeed.tech/tags/innodb.md>), [pages](<https://devfeed.tech/tags/pages.md>), [postgresql](<https://devfeed.tech/tags/postgresql.md>), [query](<https://devfeed.tech/tags/query.md>), [storage](<https://devfeed.tech/tags/storage.md>), [vacuum](<https://devfeed.tech/tags/vacuum.md>)

### AI overview

This tutorial explains why a normal index scan may still be slow: after finding matching entries, the database follows a pointer into the table for each row. Covering indexes store the selected columns in the index and can avoid those heap reads. In PostgreSQL, index-only scans also depend on the visibility map marking pages all-visible, while SELECT * prevents the technique from being fully effective.

### Source excerpt

A normal index scan finds matching rows and then follows a pointer into the table for every one of them, which is a random read per row. A covering index stores the columns the query selects, so the engine answers entirely from the index and skips those reads. In PostgreSQL this only works when the visibility map marks the pages all-visible, so an unvacuumed table will report Heap Fetches in EXPLAIN and give back most of the gain. SELECT star defeats the technique completely.

## Why your index is not being used, and why the planner is usually right

DevFeed: [Why your index is not being used, and why the planner is usually right](<https://devfeed.tech/articles/why-your-index-is-not-being-used-and-why-the-planner-is-usually-right-39590.md>)

Original publisher: [Read original article](<https://ankit-rana.com/logs/38-why-your-index-is-not-being-used/>)

Author: hello@ankit-rana.com

Published: 2026-08-16T00:00:00Z

Content type: tutorial

Language: en

Sources: [Ankit Rana | Mechanical Sympathy](<https://devfeed.tech/sources/ankit-rana-mechanical-sympathy.md>)

Topics: [Query (disambiguation)](<https://devfeed.tech/topics/query.md>), [MySQL](<https://devfeed.tech/topics/mysql.md>), [bug](<https://devfeed.tech/topics/bug.md>)

Tags: [bug](<https://devfeed.tech/tags/bug.md>), [cardinality](<https://devfeed.tech/tags/cardinality.md>), [database-performance](<https://devfeed.tech/tags/database-performance.md>), [explain](<https://devfeed.tech/tags/explain.md>), [function](<https://devfeed.tech/tags/function.md>), [indexes](<https://devfeed.tech/tags/indexes.md>), [indexing](<https://devfeed.tech/tags/indexing.md>), [mysql](<https://devfeed.tech/tags/mysql.md>), [postgresql](<https://devfeed.tech/tags/postgresql.md>), [predicate](<https://devfeed.tech/tags/predicate.md>), [query](<https://devfeed.tech/tags/query.md>), [query-planner](<https://devfeed.tech/tags/query-planner.md>)

### AI overview

This tutorial explains why database indexes may not be used even when they exist. It focuses on inaccurate cardinality estimates caused by stale statistics, predicates that prevent index matching, implicit casts, and cases where sequential scans are the cheaper choice.

### Source excerpt

An unused index is almost never a planner bug. It is usually a predicate the planner cannot match to the index, such as a function or an implicit cast applied to the column, or a cardinality estimate that is wrong because statistics are stale. When the estimate is right and the planner still refuses, it is often correct: past a few percent of the table, random access through an index costs more than reading the table sequentially. The diagnostic that matters is the gap between estimated and actual rows in EXPLAIN ANALYZE.

## How fsync affects data durability, latency, and group commit

DevFeed: [How fsync affects data durability, latency, and group commit](<https://devfeed.tech/articles/fsync-is-the-only-thing-between-you-and-data-loss-and-it-is-slower-than-you-think-39589.md>)

Original publisher: [Read original article](<https://ankit-rana.com/logs/37-fsync-durability-cost-group-commit/>)

Author: hello@ankit-rana.com

Published: 2026-08-14T00:00:00Z

Content type: article

Language: en

Sources: [Ankit Rana | Mechanical Sympathy](<https://devfeed.tech/sources/ankit-rana-mechanical-sympathy.md>)

Topics: [data](<https://devfeed.tech/topics/data.md>), [Latency](<https://devfeed.tech/topics/latency.md>), [NVMe](<https://devfeed.tech/topics/nvme.md>), [Replication](<https://devfeed.tech/topics/replication.md>)

Tags: [databases](<https://devfeed.tech/tags/databases.md>), [durability](<https://devfeed.tech/tags/durability.md>), [flush](<https://devfeed.tech/tags/flush.md>), [fsync](<https://devfeed.tech/tags/fsync.md>), [postgresql](<https://devfeed.tech/tags/postgresql.md>), [replication](<https://devfeed.tech/tags/replication.md>), [ssd](<https://devfeed.tech/tags/ssd.md>), [stack](<https://devfeed.tech/tags/stack.md>), [storage](<https://devfeed.tech/tags/storage.md>)

### AI overview

This article explains that a successful write() may leave data only in the kernel page cache, so a power loss can destroy it. It describes fsync as the operation that pushes data to the device, discusses its latency cost, and explains how group commit amortizes the synchronization barrier. It also distinguishes disk durability from replication across failure domains.

### Source excerpt

A successful write() only copies your data into the kernel page cache, where a power loss destroys it. Only fsync pushes it to the device, and because fsync is a barrier rather than a write, a system that syncs once per commit is capped at roughly one divided by the fsync latency, no matter how fast the rest of the stack is. Group commit exists to amortise that barrier, and replication solves a different failure domain than fsync does, which is why acks=all does not mean the data is on any disk.

## Why CRUD APIs Stop Teaching New Lessons After Basic Production Problems Are Solved

DevFeed: [Why CRUD APIs Stop Teaching New Lessons After Basic Production Problems Are Solved](<https://devfeed.tech/articles/boredom-is-a-signal-to-find-a-harder-problem-when-your-crud-api-stops-teaching-you-39585.md>)

Original publisher: [Read original article](<https://ankit-rana.com/logs/33-game-of-life-boredom-harder-problem/>)

Author: hello@ankit-rana.com

Published: 2026-08-02T00:00:00Z

Content type: opinion

Language: en

Sources: [Ankit Rana | Mechanical Sympathy](<https://devfeed.tech/sources/ankit-rana-mechanical-sympathy.md>)

Topics: [CRUD](<https://devfeed.tech/topics/crud.md>), [REST API](<https://devfeed.tech/topics/rest-api.md>), [Back end](<https://devfeed.tech/topics/backend.md>), [SQL](<https://devfeed.tech/topics/sql.md>), [Latency](<https://devfeed.tech/topics/latency.md>), [Network](<https://devfeed.tech/topics/network.md>), [Redis](<https://devfeed.tech/topics/redis.md>)

Tags: [api](<https://devfeed.tech/tags/api.md>), [backend](<https://devfeed.tech/tags/backend.md>), [cache-invalidation](<https://devfeed.tech/tags/cache-invalidation.md>), [career](<https://devfeed.tech/tags/career.md>), [crud](<https://devfeed.tech/tags/crud.md>), [latency](<https://devfeed.tech/tags/latency.md>), [learning](<https://devfeed.tech/tags/learning.md>), [network](<https://devfeed.tech/tags/network.md>), [schema](<https://devfeed.tech/tags/schema.md>), [schema-design](<https://devfeed.tech/tags/schema-design.md>), [system-design](<https://devfeed.tech/tags/system-design.md>)

### AI overview

A small CRUD API teaches backend fundamentals such as validation, schema design, migrations, query behavior, connection pooling, and cache invalidation. After those issues are understood, developers may need more complex failure domains involving cross-service contracts, event ordering, and slow downstream calls to continue learning.

### Source excerpt

A todo CRUD API teaches real things, including validation, schema design, the N+1 query, index selection, pool sizing, and cache invalidation, and then it goes quiet. Boredom arriving right after you fix those once is not laziness; it is the signal that the problem stopped presenting decisions you have not already seen. The move is up the stack, to a failure domain with cross-service contracts, event ordering, and downstream calls that hang.

## Promotions are Proactive: The 3P Framework for Pitching Your Next Level

DevFeed: [Promotions are Proactive: The 3P Framework for Pitching Your Next Level](<https://devfeed.tech/articles/promotions-are-proactive-the-3p-framework-for-pitching-your-next-level-39583.md>)

Original publisher: [Read original article](<https://ankit-rana.com/logs/31-promotions-proactive-3p-framework/>)

Author: hello@ankit-rana.com

Published: 2026-08-02T00:00:00Z

Content type: opinion

Language: en

Sources: [Ankit Rana | Mechanical Sympathy](<https://devfeed.tech/sources/ankit-rana-mechanical-sympathy.md>)

Topics: [Back end](<https://devfeed.tech/topics/backend.md>), [Latency](<https://devfeed.tech/topics/latency.md>), [Caching](<https://devfeed.tech/topics/caching.md>), [connection pool](<https://devfeed.tech/topics/connection-pool.md>), [migration](<https://devfeed.tech/topics/migration.md>)

Tags: [backend](<https://devfeed.tech/tags/backend.md>), [caching](<https://devfeed.tech/tags/caching.md>), [career](<https://devfeed.tech/tags/career.md>), [career-growth](<https://devfeed.tech/tags/career-growth.md>), [connection-pool](<https://devfeed.tech/tags/connection-pool.md>), [engineering](<https://devfeed.tech/tags/engineering.md>), [latency](<https://devfeed.tech/tags/latency.md>), [leadership](<https://devfeed.tech/tags/leadership.md>), [migration](<https://devfeed.tech/tags/migration.md>), [scope](<https://devfeed.tech/tags/scope.md>), [system-design](<https://devfeed.tech/tags/system-design.md>)

### AI overview

This article presents the 3P framework--Problem, Proof, and Proactive pitch--for making an engineer's promotion case legible before review. It argues that promotion reflects the scope or blast radius of decisions, supported by system evidence and an explicit pitch.

### Source excerpt

Promotion committees do not promote effort, they promote scope, and scope has to be legible before the vote rather than explained after it fails. Strip the leveling-guide language and the question is blast radius: a mid-level engineer's bad call fails one deploy unit, a senior's saturates a pool at 2 AM across teams. The 3P framework makes that visible: Problem at org scale, Proof in system metrics, and a Proactive pitch.

## Implementing LFU Cache in O(1) Time: A Hands-on Breakdown

DevFeed: [Implementing LFU Cache in O(1) Time: A Hands-on Breakdown](<https://devfeed.tech/articles/implementing-lfu-cache-in-o-1-time-a-hands-on-breakdown-39586.md>)

Original publisher: [Read original article](<https://ankit-rana.com/logs/34-lfu-cache-o1-implementation/>)

Author: hello@ankit-rana.com

Published: 2026-08-02T00:00:00Z

Content type: tutorial

Language: en

Sources: [Ankit Rana | Mechanical Sympathy](<https://devfeed.tech/sources/ankit-rana-mechanical-sympathy.md>)

Topics: [Cache](<https://devfeed.tech/topics/cache.md>), [Caching](<https://devfeed.tech/topics/caching.md>), [Data structures](<https://devfeed.tech/topics/data-structures.md>), [implementation](<https://devfeed.tech/topics/implementation.md>)

Tags: [algorithms](<https://devfeed.tech/tags/algorithms.md>), [cache](<https://devfeed.tech/tags/cache.md>), [caching](<https://devfeed.tech/tags/caching.md>), [implementing](<https://devfeed.tech/tags/implementing.md>), [java](<https://devfeed.tech/tags/java.md>), [lfu](<https://devfeed.tech/tags/lfu.md>), [memory](<https://devfeed.tech/tags/memory.md>), [order](<https://devfeed.tech/tags/order.md>), [performance](<https://devfeed.tech/tags/performance.md>), [pointers](<https://devfeed.tech/tags/pointers.md>), [system-design](<https://devfeed.tech/tags/system-design.md>)

### AI overview

This tutorial explains why LRU can evict a frequently requested product during a long-tail burst, then presents an O(1) LFU cache design. It contrasts a naive O(n) eviction scan with an implementation using key-to-node and frequency-to-bucket maps, doubly linked lists, and a minFreq pointer.

### Source excerpt

LFU evicts the least frequently used key rather than the least recently used, which protects a hot key during a long-tail burst that would make LRU drop a bestseller. The naive implementation scans every key to find the minimum frequency, which is O(n) per eviction. The O(1) version inverts the index: a key-to-node map, a frequency-to-bucket map of doubly linked lists, and a minFreq pointer.

## AI speeds up code writing, but coordination across distributed services remains a system-design challenge

DevFeed: [AI speeds up code writing, but coordination across distributed services remains a system-design challenge](<https://devfeed.tech/articles/glue-work-is-the-new-system-design-why-alignment-is-the-premium-skill-in-the-age-of-ai-39582.md>)

Original publisher: [Read original article](<https://ankit-rana.com/logs/30-glue-work-new-system-design/>)

Author: hello@ankit-rana.com

Published: 2026-08-02T00:00:00Z

Content type: opinion

Language: en

Sources: [Ankit Rana | Mechanical Sympathy](<https://devfeed.tech/sources/ankit-rana-mechanical-sympathy.md>)

Topics: [Artificial Intelligence](<https://devfeed.tech/topics/ai.md>), [distributed-systems](<https://devfeed.tech/topics/distributed-systems.md>), [backends](<https://devfeed.tech/topics/backends.md>), [Microservice](<https://devfeed.tech/topics/microservice.md>), [migration](<https://devfeed.tech/topics/migration.md>), [OpenAPI Specification](<https://devfeed.tech/topics/openapi.md>)

Tags: [ai](<https://devfeed.tech/tags/ai.md>), [alignment](<https://devfeed.tech/tags/alignment.md>), [architecture](<https://devfeed.tech/tags/architecture.md>), [backend](<https://devfeed.tech/tags/backend.md>), [distributed-systems](<https://devfeed.tech/tags/distributed-systems.md>), [migration](<https://devfeed.tech/tags/migration.md>), [openapi](<https://devfeed.tech/tags/openapi.md>), [services](<https://devfeed.tech/tags/services.md>), [system-design](<https://devfeed.tech/tags/system-design.md>)

### AI overview

The article argues that AI assistants have accelerated implementation work while leaving coordination between teams and services largely unchanged. It presents ownership boundaries, contract stability, migration coordination, and failure semantics as central system-design concerns because failures often occur between otherwise correct components.

### Source excerpt

AI made the write path fast and left the coordination path untouched, so failures now live in the gaps between services: two event schema versions across two regions, three teams, and one assumption that someone else handled the migration window. Alignment work, deciding ownership boundaries, contract stability, and failure semantics before anyone opens an IDE, is system design, and it produces concrete network cost when skipped.

## How ORM N+1 Queries Create Hidden Request Latency

DevFeed: [How ORM N+1 Queries Create Hidden Request Latency](<https://devfeed.tech/articles/your-orm-issued-400-queries-and-the-p99-looked-fine-until-it-didn-t-39588.md>)

Original publisher: [Read original article](<https://ankit-rana.com/logs/36-orm-n-plus-one-queries-hidden-latency/>)

Author: hello@ankit-rana.com

Published: 2026-08-02T00:00:00Z

Content type: tutorial

Language: en

Sources: [Ankit Rana | Mechanical Sympathy](<https://devfeed.tech/sources/ankit-rana-mechanical-sympathy.md>)

Topics: [Object-relational mapping](<https://devfeed.tech/topics/orm.md>), [Latency](<https://devfeed.tech/topics/latency.md>), [Monitoring](<https://devfeed.tech/topics/monitoring.md>), [lazy loading](<https://devfeed.tech/topics/lazy-loading.md>), [Database](<https://devfeed.tech/topics/database.md>), [connection pool](<https://devfeed.tech/topics/connection-pool.md>)

Tags: [connection-pool](<https://devfeed.tech/tags/connection-pool.md>), [database](<https://devfeed.tech/tags/database.md>), [database-performance](<https://devfeed.tech/tags/database-performance.md>), [hibernate](<https://devfeed.tech/tags/hibernate.md>), [latency](<https://devfeed.tech/tags/latency.md>), [lazy-loading](<https://devfeed.tech/tags/lazy-loading.md>), [monitoring](<https://devfeed.tech/tags/monitoring.md>), [n-plus-one](<https://devfeed.tech/tags/n-plus-one.md>), [observability](<https://devfeed.tech/tags/observability.md>), [orm](<https://devfeed.tech/tags/orm.md>), [query](<https://devfeed.tech/tags/query.md>), [request](<https://devfeed.tech/tags/request.md>)

### AI overview

This article explains how ORM lazy loading can turn a loop over orders into an N+1 query pattern. Individual queries may remain fast and avoid slow-query alerts, while the accumulated network round trips increase request latency and hold connection-pool resources. It recommends monitoring queries per request and asserting query counts in tests.

### Source excerpt

N+1 queries hide from monitoring because no individual query is slow. Four hundred queries at 0.4ms each never appear in the slow query log, never move p99 query latency, and still cost the request 300ms because the expense is the round trip rather than the execution. The metric that catches it is queries per request, and the only durable fix is asserting on that count in tests, since the code that causes it looks like a field access rather than I/O.

## I Rebuilt a Minimal BitTorrent Client in Go to Understand Peer-to-Peer Choking Algorithms

DevFeed: [I Rebuilt a Minimal BitTorrent Client in Go to Understand Peer-to-Peer Choking Algorithms](<https://devfeed.tech/articles/i-rebuilt-a-minimal-bittorrent-client-in-go-to-understand-peer-to-peer-choking-algorithms-39584.md>)

Original publisher: [Read original article](<https://ankit-rana.com/logs/32-minimal-bittorrent-choking-algorithms-go/>)

Author: hello@ankit-rana.com

Published: 2026-08-02T00:00:00Z

Content type: tutorial

Language: en

Sources: [Ankit Rana | Mechanical Sympathy](<https://devfeed.tech/sources/ankit-rana-mechanical-sympathy.md>)

Topics: [Algorithms](<https://devfeed.tech/topics/algorithms.md>), [P2P](<https://devfeed.tech/topics/p2p.md>), [Go Language](<https://devfeed.tech/topics/go-language.md>), [Programming](<https://devfeed.tech/topics/programming.md>), [Network](<https://devfeed.tech/topics/network.md>)

Tags: [algorithms](<https://devfeed.tech/tags/algorithms.md>), [bittorrent](<https://devfeed.tech/tags/bittorrent.md>), [distributed-systems](<https://devfeed.tech/tags/distributed-systems.md>), [go](<https://devfeed.tech/tags/go.md>), [golang](<https://devfeed.tech/tags/golang.md>), [network](<https://devfeed.tech/tags/network.md>), [networking](<https://devfeed.tech/tags/networking.md>), [p2p](<https://devfeed.tech/tags/p2p.md>), [peer-to-peer](<https://devfeed.tech/tags/peer-to-peer.md>), [protocol](<https://devfeed.tech/tags/protocol.md>), [system-design](<https://devfeed.tech/tags/system-design.md>)

### AI overview

A hands-on explanation of BitTorrent choking algorithms through rebuilding a minimal client in Go. The article describes choking as a decentralized bandwidth-allocation mechanism, explains the choked and interested states, and shows how upload capacity affects peer prioritization.

### Source excerpt

The BitTorrent spec explains choking in two paragraphs; implementing it in Go and watching every peer choke you within 60 seconds is what makes it stick. Choking is a bandwidth allocator running independently on every node, not a courtesy flag. Upload is the scarce resource on an asymmetric link, and each connection carries just two booleans, choked and interested, whose four combinations drive the entire fairness policy of the swarm.

## Decoding isolation levels: I built a toy DB to force dirty reads and phantom reads

DevFeed: [Decoding isolation levels: I built a toy DB to force dirty reads and phantom reads](<https://devfeed.tech/articles/decoding-isolation-levels-i-built-a-toy-db-to-force-dirty-reads-and-phantom-reads-39587.md>)

Original publisher: [Read original article](<https://ankit-rana.com/logs/35-isolation-levels-toy-db-dirty-phantom-reads/>)

Author: hello@ankit-rana.com

Published: 2026-08-02T00:00:00Z

Content type: tutorial

Language: en

Sources: [Ankit Rana | Mechanical Sympathy](<https://devfeed.tech/sources/ankit-rana-mechanical-sympathy.md>)

Topics: [Databases](<https://devfeed.tech/topics/databases.md>), [PostgreSQL](<https://devfeed.tech/topics/postgresql.md>), [Python](<https://devfeed.tech/topics/python.md>), [MySQL](<https://devfeed.tech/topics/mysql.md>), [SQL](<https://devfeed.tech/topics/sql.md>), [locking](<https://devfeed.tech/topics/locking.md>)

Tags: [concurrency](<https://devfeed.tech/tags/concurrency.md>), [databases](<https://devfeed.tech/tags/databases.md>), [isolation-levels](<https://devfeed.tech/tags/isolation-levels.md>), [locking](<https://devfeed.tech/tags/locking.md>), [mvcc](<https://devfeed.tech/tags/mvcc.md>), [mysql](<https://devfeed.tech/tags/mysql.md>), [postgres](<https://devfeed.tech/tags/postgres.md>), [postgresql](<https://devfeed.tech/tags/postgresql.md>), [python](<https://devfeed.tech/tags/python.md>), [sql](<https://devfeed.tech/tags/sql.md>), [transactions](<https://devfeed.tech/tags/transactions.md>)

### AI overview

A hands-on tutorial uses a roughly 200-line Python toy database to reproduce transaction anomalies and explain why isolation levels behave differently across PostgreSQL and MySQL InnoDB. It shows that the ANSI SQL isolation table does not fully describe engine behavior, including PostgreSQL's handling of READ UNCOMMITTED and REPEATABLE READ, and MySQL InnoDB's snapshot and next-key locking behavior.

### Source excerpt

The ANSI isolation table lists which anomalies each level permits, but it does not describe what your engine actually does: Postgres silently upgrades READ UNCOMMITTED to READ COMMITTED, and its REPEATABLE READ prevents phantoms that the standard allows. Phantom reads are a locking problem rather than a row problem, because you cannot lock a row that does not exist yet. Snapshot isolation stops every anomaly the table names and still permits write skew, which the table never mentions.

[Next page](<https://devfeed.tech/sources/ankit-rana-mechanical-sympathy.md?cursor=WyIyMDI2LTA4LTAyVDAwOjAwOjAwKzAwOjAwIiwgIjBkODIxNzIwLWVmYTUtNDQ1Yy05MjQyLTVlMjc0M2YxZTQwMiJd>)