<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Labeeb Ahmad</title>
    <description>The latest articles on DEV Community by Labeeb Ahmad (@labeeb-ahmad).</description>
    <link>https://dev.to/labeeb-ahmad</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F217777%2F21e6635b-eac9-4a12-a671-a9980e796deb.jpg</url>
      <title>DEV Community: Labeeb Ahmad</title>
      <link>https://dev.to/labeeb-ahmad</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/labeeb-ahmad"/>
    <language>en</language>
    <item>
      <title>Lessons from the Axios Hack</title>
      <dc:creator>Labeeb Ahmad</dc:creator>
      <pubDate>Wed, 01 Apr 2026 07:52:01 +0000</pubDate>
      <link>https://dev.to/labeeb-ahmad/lessons-from-the-axios-hack-98i</link>
      <guid>https://dev.to/labeeb-ahmad/lessons-from-the-axios-hack-98i</guid>
      <description>&lt;p&gt;Last week, the popular axios library was compromised. A maintainer’s npm account was stolen, and two malicious versions were published for a few hours. Anyone who ran npm install during that window automatically pulled in malware that stole credentials and keys.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why did so many people get hit?&lt;/strong&gt; Because most dependencies are written with a caret:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"axios"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^1.14.0"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That caret means “get the latest minor or patch version.” When the malicious 1.14.1 came out, every npm install grabbed it without asking.&lt;/p&gt;

&lt;p&gt;The fix is simple: pin exact versions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"axios"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.14.0"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now your project never upgrades unless you manually change the number.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What about package-lock.json?&lt;/strong&gt; A lock file records what was installed at a specific time. If yours was created before the attack, you were safe. But if you regenerated it during the attack window, it would have locked in the bad version. So a lock file helps, but it’s not a substitute for pinning.&lt;/p&gt;

&lt;p&gt;When you do upgrade:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wait a few days after a new release.&lt;/li&gt;
&lt;li&gt;Check GitHub issues and advisories.&lt;/li&gt;
&lt;li&gt;Use npm audit before updating.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;One more thing:&lt;/strong&gt; AI assistants often suggest npm install commands without knowing about today’s security incidents. Take a second to verify the version you’re about to install.&lt;/p&gt;

&lt;p&gt;Pin exact versions. Upgrade deliberately. It’s a small habit that stops attacks like this.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>TLS Handshake Explained: How HTTPS Actually Works</title>
      <dc:creator>Labeeb Ahmad</dc:creator>
      <pubDate>Mon, 30 Mar 2026 18:51:03 +0000</pubDate>
      <link>https://dev.to/labeeb-ahmad/tls-handshake-explained-how-https-actually-works-1eo0</link>
      <guid>https://dev.to/labeeb-ahmad/tls-handshake-explained-how-https-actually-works-1eo0</guid>
      <description>&lt;p&gt;When you type https:// into your browser, a lot happens before you see the webpage. HTTPS is not a separate protocol. It is simply HTTP (the web protocol) running inside a TLS security tunnel that is carried over TCP (the reliable transport). This article walks through each layer, explains the TLS handshake, and shows how certificates are verified.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Foundation: TCP
&lt;/h2&gt;

&lt;p&gt;TCP (Transmission Control Protocol) is the workhorse that delivers data reliably between two machines. Before any application data can be sent, the client and server perform a three‑way handshake:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SYN client says “I want to connect.”&lt;/li&gt;
&lt;li&gt;SYN‑ACK  server agrees.&lt;/li&gt;
&lt;li&gt;ACK  client confirms.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After this, a bidirectional, ordered, error‑checked channel exists. TCP does not encrypt anything; it just moves bytes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Security Layer: TLS
&lt;/h2&gt;

&lt;p&gt;TLS (Transport Layer Security) is a protocol that runs on top of TCP. Its job is to turn the plain TCP pipe into an encrypted, authenticated, and integrity‑protected tunnel. The process of setting up this tunnel is called the TLS handshake.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Handshake Achieves
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Negotiation: client and server agree on a TLS version and cipher suite.&lt;/li&gt;
&lt;li&gt;Authentication: the server proves its identity using a digital certificate.&lt;/li&gt;
&lt;li&gt;Key exchange: both sides create a shared secret that only they know.&lt;/li&gt;
&lt;li&gt;Verification: they confirm that the handshake wasn’t tampered with.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Simplified Handshake Steps
&lt;/h2&gt;

&lt;p&gt;The following diagram shows the messages exchanged. Note that the first three messages happen over the already‑established TCP connection.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0a6u8xgx2b8df7k6dslm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0a6u8xgx2b8df7k6dslm.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ClientHello – client sends supported TLS versions, cipher suites, and a random number. &lt;/li&gt;
&lt;li&gt;ServerHello – server picks a version and cipher suite, sends its own random number. &lt;/li&gt;
&lt;li&gt;Certificate – server sends its certificate (contains its long‑term public key, domain, and a CA signature). &lt;/li&gt;
&lt;li&gt;ServerKeyExchange – server sends an ephemeral (temporary) public key, signed with its long‑term private key. &lt;/li&gt;
&lt;li&gt;ClientKeyExchange – client sends its ephemeral public key. &lt;/li&gt;
&lt;li&gt;ChangeCipherSpec – signals that subsequent messages will be encrypted. &lt;/li&gt;
&lt;li&gt;Finished – both sides send an encrypted hash of the handshake to confirm it was not tampered with.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After the handshake, the actual HTTP data is sent inside encrypted TLS records.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Purpose of ChangeCipherSpec
&lt;/h2&gt;

&lt;p&gt;The ChangeCipherSpec message is a simple indicator that tells the other side: “From this point forward, I will encrypt all messages using the session keys we just agreed on.” It synchronises the encryption state. The Finished message that follows is the first encrypted message; it includes a hash of the entire handshake, allowing both sides to verify that no one tampered with the handshake.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the Browser Verifies a Certificate
&lt;/h2&gt;

&lt;p&gt;When the server sends its certificate, the browser must decide whether to trust it. It does not contact the Certificate Authority (CA) for every connection. Instead, it performs these checks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chain of trust – The server’s certificate is usually not directly signed by a root CA. Instead, it’s signed by an intermediate CA, which is signed by a root CA. The server sends the full chain (its certificate + intermediates). The browser checks that each certificate in the chain is valid and that the root CA is in its trust store (a pre‑installed list of trusted root certificates that comes with the operating system or browser).&lt;/li&gt;
&lt;li&gt;Digital signature verification – Using the public key of the root CA (which is pre‑trusted), the browser verifies the signature on the intermediate certificate. Then, using the intermediate’s public key, it verifies the signature on the server’s certificate. If the signatures match, the browser knows that the server’s public key is vouched for by a trusted CA.&lt;/li&gt;
&lt;li&gt;Domain name – the certificate’s Subject Alternative Name (SAN) or Common Name must match the domain in the URL.&lt;/li&gt;
&lt;li&gt;Expiration – the certificate must be valid now.&lt;/li&gt;
&lt;li&gt;Revocation (optional) – the browser may check with the CA to see if the certificate has been revoked before its expiration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If all checks pass, the browser accepts the server’s public key as authentic. If any check fails, the browser shows a security warning.&lt;/p&gt;

&lt;p&gt;This process happens entirely on the client side—no live call to the CA is required for the basic signature verification, because the root CA’s public key is already trusted and stored locally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Do the Private Keys Come From?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Browser (client): For each new connection, the browser generates a temporary (ephemeral) private key entirely in memory. This key is used only during the handshake to compute the shared secret, then discarded. It is never transmitted.&lt;/li&gt;
&lt;li&gt;Server: The server also generates a temporary ephemeral private key for each session. This key is used together with the browser’s ephemeral public key to compute the shared secret. In addition, the server has a long‑term private key that corresponds to the public key inside its TLS certificate. This long‑term key is never used for encryption; it is used only to digitally sign the server’s ephemeral public key during the handshake, proving that the ephemeral key belongs to the legitimate server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The diagram below shows the flow from ephemeral keys to the symmetric session keys that actually encrypt the HTTP data:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqb7tzzop53fb7u8lkgk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqb7tzzop53fb7u8lkgk.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How is the actual HTTP data encrypted?&lt;/strong&gt; From the shared secret derived during the handshake, both sides independently generate symmetric session keys (the same keys on both ends). These symmetric keys are used to encrypt and decrypt all HTTP traffic. The ephemeral private keys and the server’s long‑term private key are never used to encrypt or decrypt the web content itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why forward secrecy?&lt;/strong&gt; Because the shared secret is derived solely from the ephemeral key pair, the long‑term private key is only used for signing. Even if an attacker later steals the server’s long‑term private key, they cannot decrypt past sessions, the ephemeral keys used for those sessions are gone. This is forward secrecy.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Application Layer: HTTP
&lt;/h2&gt;

&lt;p&gt;HTTP (Hypertext Transfer Protocol) is the language of the web requests like GET /index.html and responses with status codes and content. In HTTPS, HTTP messages are never sent in the clear over the network; they are placed inside the encrypted TLS tunnel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting It Together: HTTPS
&lt;/h2&gt;

&lt;p&gt;HTTPS is not a separate protocol; it’s a URI scheme that tells the client: "Use HTTP, but wrap it in TLS over TCP." The formal description is HTTP over TLS over TCP.&lt;/p&gt;

&lt;p&gt;So when you see a padlock in your browser, you know the stack is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP
│
TLS (encryption + authentication)
│
TCP (reliable transport)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;TCP provides reliable transport.&lt;/li&gt;
&lt;li&gt;TLS adds encryption, authentication, and integrity on top of TCP.&lt;/li&gt;
&lt;li&gt;HTTP is the application protocol that runs inside the TLS tunnel.&lt;/li&gt;
&lt;li&gt;HTTPS is simply HTTP over TLS over TCP – a scheme, not a separate protocol.&lt;/li&gt;
&lt;li&gt;The TLS handshake negotiates parameters, authenticates the server, establishes ephemeral keys, and confirms the connection.&lt;/li&gt;
&lt;li&gt;Certificates are verified by building a chain of trust to a pre‑trusted root CA.&lt;/li&gt;
&lt;li&gt;Forward secrecy ensures that past sessions cannot be decrypted even if the server’s long‑term private key is later stolen.&lt;/li&gt;
&lt;li&gt;Asymmetric encryption is used only during the handshake; symmetric encryption protects the actual HTTP data.&lt;/li&gt;
&lt;li&gt;Understanding this stack helps you debug connection issues, configure TLS termination correctly, and build secure systems with confidence.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>http</category>
      <category>tcp</category>
    </item>
    <item>
      <title>The Hidden Cost of Letting AI Write Your Code</title>
      <dc:creator>Labeeb Ahmad</dc:creator>
      <pubDate>Sun, 29 Mar 2026 17:07:30 +0000</pubDate>
      <link>https://dev.to/labeeb-ahmad/the-hidden-cost-of-letting-ai-write-your-code-33nn</link>
      <guid>https://dev.to/labeeb-ahmad/the-hidden-cost-of-letting-ai-write-your-code-33nn</guid>
      <description>&lt;p&gt;There’s a comfortable lie going around. AI coding tools let you move faster, ship more, worry less. Just describe what you want, review what comes out, and get on with your life.&lt;/p&gt;

&lt;p&gt;That’s not wrong. But it’s incomplete in a way that’s going to bite a lot of people.&lt;/p&gt;

&lt;h2&gt;
  
  
  Abstractions Always Leak
&lt;/h2&gt;

&lt;p&gt;Every abstraction, no matter how elegant, eventually exposes the messy reality it was trying to hide. AI-assisted coding is an abstraction. A powerful one. But it leaks.&lt;/p&gt;

&lt;p&gt;At some point and this comes faster than people expect, you’ll hit a bug the AI can’t explain, a performance problem it can’t diagnose, or a design decision that’s quietly poisoning your system. When that moment arrives, you can’t prompt your way out. You have to think. Not the fast kind. The slow, meticulous, System-2(i.e., the slow brain) kind.&lt;/p&gt;

&lt;p&gt;That bottleneck doesn’t disappear because the AI wrote the code. It just gets deferred.&lt;/p&gt;

&lt;h2&gt;
  
  
  You Can’t Build a Mental Model You Never Had to Build
&lt;/h2&gt;

&lt;p&gt;When you write code from scratch, you’re making decisions, hitting friction, asking why. That friction is annoying. It’s also how understanding gets encoded.&lt;/p&gt;

&lt;p&gt;With AI-generated code, you get output that works, enough to pass tests, enough to ship. And because it works, there’s no obvious reason to dig deeper. You never built the model. You never had to hold the abstraction in your head long enough for it to become intuition.&lt;/p&gt;

&lt;p&gt;This shows up later when you can’t reason about the system under load, don’t know which parts are fragile, and can’t make confident decisions about what to change. You’re maintaining code you don’t really understand, except this time, you wrote it.&lt;/p&gt;

&lt;h2&gt;
  
  
  So What Do You Do?
&lt;/h2&gt;

&lt;p&gt;Read the code the AI generates, actually trace it, not just skim it. When something isn’t clear, that’s exactly the moment to slow down, not move on.&lt;/p&gt;

&lt;p&gt;The best developers using these tools aren’t the ones who trust them most. They’re the ones who know exactly when to stop trusting them. You have to question the output generated by these tools.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Finding Slow Queries in PostgreSQL (Without Guessing)</title>
      <dc:creator>Labeeb Ahmad</dc:creator>
      <pubDate>Sat, 28 Mar 2026 02:34:47 +0000</pubDate>
      <link>https://dev.to/labeeb-ahmad/finding-slow-queries-in-postgresql-without-guessing-1p5j</link>
      <guid>https://dev.to/labeeb-ahmad/finding-slow-queries-in-postgresql-without-guessing-1p5j</guid>
      <description>&lt;p&gt;Here’s the quantitative method used by DBAs and tools like pganalyze and AWS Performance Insights.&lt;/p&gt;

&lt;p&gt;Connect to your database and create the extension:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;EXTENSION&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;pg_stat_statements&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then tell PostgreSQL to load it at startup. The easiest way is with ALTER SYSTEM (no need to edit config files):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;SYSTEM&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;shared_preload_libraries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'pg_stat_statements'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now restart PostgreSQL. If you’re using Docker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker restart &amp;lt;your-pg-container-name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The extension now tracks every query, grouping similar ones together.&lt;/p&gt;

&lt;p&gt;Find the Queries That Cost the Most&lt;/p&gt;

&lt;p&gt;After the restart, run some queries so the extension collects data. Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; 
    &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;calls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total_exec_time&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;numeric&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;total_ms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mean_exec_time&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;numeric&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;avg_ms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;round&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;total_exec_time&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;numeric&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; 
          &lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total_exec_time&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;numeric&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;OVER&lt;/span&gt; &lt;span class="p"&gt;())::&lt;/span&gt;&lt;span class="nb"&gt;numeric&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;pct_of_total&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_stat_statements&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;total_exec_time&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fktlmxfwwrtzwncjwg071.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fktlmxfwwrtzwncjwg071.png" alt=" " width="800" height="171"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The pct_of_total column shows what percentage of your database’s total execution time that query pattern represents. If a query shows 50% there, optimizing it could cut your database load in half.&lt;/p&gt;

&lt;p&gt;Note: pg_stat_statements accumulates data until reset. To get fresh trends, reset with SELECT pg_stat_statements_reset(); before measuring.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decide How to Fix It
&lt;/h2&gt;

&lt;p&gt;Look at the avg_ms column:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If avg_ms is high (e.g., &amp;gt;100ms), the query itself is slow. Use EXPLAIN ANALYZE to find missing indexes or inefficient joins.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If avg_ms is low but calls is huge, the query is cheap per call but called too often. Reduce calls via caching, batching, or fixing N+1 queries.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your threshold for "high" depends on your app's latency requirements &amp;amp; context.&lt;/p&gt;

&lt;p&gt;No more guessing. With **pg_stat_statements **you can:&lt;/p&gt;

&lt;p&gt;See which queries consume the most total CPU time.&lt;/p&gt;

&lt;p&gt;Distinguish between slow queries and too‑frequent queries.&lt;/p&gt;

&lt;p&gt;This approach is data‑driven, repeatable, and used in production every day. When things get slow, you’ll know exactly where to start.&lt;/p&gt;

</description>
      <category>sql</category>
      <category>postgressql</category>
      <category>database</category>
    </item>
  </channel>
</rss>
