How Adding Two Brackets Made a Django API 8× Faster: A Real‑World Performance Debugging Tale

When a high‑traffic Django endpoint that returned a 7 MB JSON payload slowed dramatically, the author traced the bottleneck to a misuse of StreamingHttpResponse that iterated over the response string character‑by‑character, and fixing it with a simple list wrapper or HttpResponse yielded up to an eight‑fold speedup.

Tencent Architect
Tencent Architect
Tencent Architect
How Adding Two Brackets Made a Django API 8× Faster: A Real‑World Performance Debugging Tale

The story begins on a busy afternoon when the monitoring system flagged a sudden drop in success rate for the get_svr_info API, which returns information about thousands of servers. The legacy service runs on Python 2.7, Django 1.11, and MySQL 5.5, using a straightforward view that queries all servers, builds a dict for each, and returns the result via StreamingHttpResponse(json.dumps(result)). Because the response can exceed 7 MB, the high request rate caused noticeable latency spikes.

Initial Diagnosis

The author first suspected the ORM and dict construction: fetching 10 000+ rows creates a model instance per row, and each instance is converted to a dict, which is CPU‑intensive. Switching the query to Server.objects.filter(...).values(*db_fields) reduced object creation, and trimming fields based on the caller’s needs further cut work. A benchmark script measured the average latency before and after these changes, showing only a 1.12× overall speedup, far less than expected.

Exploring Other Causes

Next, the author examined JSON serialization and network transfer. Enabling gzip in Nginx compressed the 7 MB payload to ~400 KB, but total response time increased (TTFB rose from 1.07 s to 3.05 s, total from 13.67 s to 14.85 s). Local loopback tests showed a download speed of only ~573 KB/s, indicating the bottleneck was not the network but the server’s output path.

TTFB Analysis Reveals the Real Culprit

Measuring TTFB (time to first byte) and total time with curl -w showed TTFB ≈ 1 s while total ≈ 13 s, meaning the first byte was sent quickly but the body took a long time to stream. The author realized that StreamingHttpResponse expects an iterable; passing a plain string makes Python iterate over each character, resulting in ~7 million tiny chunks and massive overhead.

Correct Use of StreamingHttpResponse

According to Django documentation, a proper streaming response should provide an iterator that yields larger chunks, e.g., using a generator that yields JSON pieces as they are produced. The faulty code was effectively:

return StreamingHttpResponse(json.dumps(result), content_type="application/json")

which iterates per character. The fix is either to wrap the string in a list so it is iterated once:

return StreamingHttpResponse([json.dumps(result)], content_type="application/json")

or, since the response is not truly streamed, simply use a normal HttpResponse with a faster serializer:

return HttpResponse(fast_dumps(result), content_type="application/json")

Final Results

After applying the correct response handling, the benchmark showed a 4.00× overall speedup, with the largest payload improving by 8.21× (13.6 s → 1.7 s). Smaller payloads also benefitted proportionally. The three main optimizations were:

Replacing StreamingHttpResponse(json.dumps(...)) with HttpResponse(fast_dumps(...)) (largest gain).

Using .values() to avoid model instance creation.

Trimming unnecessary fields based on the fields parameter.

Key Takeaways

The investigation highlights the importance of measuring TTFB to distinguish between server‑side processing and output bottlenecks, and warns that misusing streaming APIs can introduce hidden performance penalties that scale with response size. Even seemingly harmless code can become a "fake streaming" nightmare, turning a fast JSON generation into a slow per‑character dump.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

PerformanceOptimizationPythonJSONDjangoormstreaminghttpresponse
Tencent Architect
Written by

Tencent Architect

We share insights on storage, computing, networking and explore leading industry technologies together.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.