<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Write Ahead</title><description>Software Engineer, builder, and dad — writing about what I make and explore.</description><link>https://abhimanyunagurkar.com/</link><language>en-us</language><item><title>Postgres Concurrency Internals: Connections, Locks, and MVCC</title><link>https://abhimanyunagurkar.com/blog/postgres-concurrency-internals/</link><guid isPermaLink="true">https://abhimanyunagurkar.com/blog/postgres-concurrency-internals/</guid><description>A practical guide to how Postgres handles many concurrent clients — process-per-connection, pooling, lock manager, MVCC tuples, deadlocks, and pg_locks.</description><pubDate>Sun, 17 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;You run &lt;code&gt;ALTER TABLE&lt;/code&gt; on the busy &lt;code&gt;orders&lt;/code&gt; table and every query in the cluster freezes for forty seconds. A Python script hangs with one open transaction overnight, and the next &lt;code&gt;VACUUM&lt;/code&gt; runs for an hour. The dashboard that’s fast for you takes three seconds for the user sitting next to you, on the same data. Most of the day-to-day weirdness in a production database comes from many clients talking to it at once, and someone holding something they shouldn’t be.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;/blog/acid-properties-and-isolation-levels/&quot;&gt;previous post&lt;/a&gt; covered the &lt;em&gt;semantics&lt;/em&gt; of concurrency — which isolation level to pick, what each one guarantees, where the anomalies come from. This post is the &lt;em&gt;mechanics&lt;/em&gt;: what actually happens when your connection hits Postgres, where the locks live, why MVCC lets readers and writers coexist, and how to figure out who’s blocking whom at 3 AM. Same database, different layer.&lt;/p&gt;
&lt;p&gt;Part 8 of the Database Internals series.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;1-the-connection-model&quot;&gt;1. The Connection Model&lt;/h2&gt;
&lt;p&gt;Every Postgres client connection is a &lt;strong&gt;separate OS process&lt;/strong&gt; on the database server. There is no thread pool inside Postgres. There is no event loop multiplexing connections onto a small number of workers. When &lt;code&gt;psql&lt;/code&gt; connects, an entire &lt;code&gt;postgres&lt;/code&gt; process is forked for it, lives until the client disconnects, and dies when the client goes away.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;postmaster&lt;/code&gt; is the supervisor process. It listens on the TCP port, accepts an incoming connection, authenticates the client, then &lt;code&gt;fork()&lt;/code&gt;s a new &lt;strong&gt;backend process&lt;/strong&gt; to serve that client for its lifetime. The backend executes queries, owns its own local memory (&lt;code&gt;work_mem&lt;/code&gt;, &lt;code&gt;temp_buffers&lt;/code&gt;), and reaches into shared memory (&lt;code&gt;shared_buffers&lt;/code&gt;, the WAL buffers, the lock table) for anything cluster-wide.&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 928 1062&quot;&gt;&lt;svg class=&quot;d2-2166466768 d2-svg&quot; width=&quot;928&quot; height=&quot;1062&quot; viewBox=&quot;-13 27 928 1062&quot;&gt;&lt;rect x=&quot;-13.000000&quot; y=&quot;27.000000&quot; width=&quot;928.000000&quot; height=&quot;1062.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-2166466768 .text {
	font-family: &quot;d2-2166466768-font-regular&quot;;
}
@font-face {
	font-family: d2-2166466768-font-regular;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-2166466768 .text-italic {
	font-family: &quot;d2-2166466768-font-italic&quot;;
}
@font-face {
	font-family: d2-2166466768-font-italic;
	src: url(&quot;data:application/font-woff;base64,d09GRgABAAAAABFQAAoAAAAAGqAAARhRAAAAAAAAAAAAAAAAAAAAAAAAAABPUy8yAAAA9AAAAGAAAABgW1SVeGNtYXAAAAFUAAAAsgAAAOwEzwUuZ2x5ZgAAAggAAApvAAAOwHJK0O5oZWFkAAAMeAAAADYAAAA2G7Ur2mhoZWEAAAywAAAAJAAAACQLeAjSaG10eAAADNQAAACzAAAAuFFZBCJsb2NhAAANiAAAAF4AAABeWfxWMm1heHAAAA3oAAAAIAAAACAARgD2bmFtZQAADggAAAMmAAAIMgntVzNwb3N0AAARMAAAACAAAAAg/8YAMgADAeEBkAAFAAACigJY//EASwKKAlgARAFeADIBIwAAAgsFAwMEAwkCBCAAAHcAAAADAAAAAAAAAABBREJPAAEAIP//Au7/BgAAA9gBESAAAZMAAAAAAeYClAAAACAAA3icfM3LKrQBAIfx3/u98zmOMc7n8TrPoGThApSNslDUrC1lLbkkbCUlC3fCLVhP/dVk7dn+Fg8KpQJ1NZ9oaSo1VDr2HThy4tSZc5e6rt26T1Bp9/3Q8a9f6Lpy4y7JlyK99PKdj7znLa95yXOe8piH/u2vCh272vZs2LRl245/SjX/DRg0ZNiIUXVjGsY1TZg0ZdqMWXPmLVi0ZNmKllWVNev8AAAA//8BAAD//9lCJ+cAAHicfFdpcBvlGX6/b9daH/IhrY5IsSRLK+3K8kqydyWtZVuSZfmQbcln7DiHjxAS4sQFNyFcSbgyk7ZpyYgOU6YMbRigHTr8KJP0RykUZihtDdQzbSft0NJjymEgKQN4XAoMXnV2Jduyf/SP/I139nvf53nf53nfhTJwA+Bb8SNAQAXUgh6MACLtJAhRkhgzIXIcQ1ESR9OU+0G09OBjZGr/e94nvuAdZN8DPxn899yz+JH1BXT/9H33yQe+eeTI3hs3ZB/68w0AAJx/AwD9CeegAnQANCVyLMsxGg1CIs1wDPVO268qyUqStIry79DN+zOj+g/m0d2Li6HjrdFb5FGcW19cXgYggAHADTgHOrAqZ5EWBZPRoNFQlEn9yxCiEAmHWGbrwJz/6exCU8qNxN6+s0NtMzP7ewYOnDg5c2u2/3acG+jju/lyUpts7Z/m0R19kl9Yv96TEWJK3gii+TXsx4+DA6DMxbLhUByLgslMsSzjqsFGg8kkChHJrNEg1+CxSPP+c5nW0V0ROsK2zXa5XQPt3lQD457Wpu4ayj5yZ5/ka2zgYjff1dE+HW7YLTj8CjcqpojKDV2CiOFEIbKB4J5vPTRx+bbJyYmzqVsOR3DuG3ff+bMjnXu+d2h6vpAnAwBrOAeEegPBnB86r5C28Qx9F+egrPDMSTHnh+5AhmqcW7/SVYzvxzmoAkNpfIagtyh8/uDJgQf2zIeSs0eOZ9JHcG5gcuSWFvlz1DcyHBULOWjza0jGj4MPwOxiOUnlJhxiOU4hLhLZJE6jMRpMZnOhYu+nFr1R24TUMer3ZHzt4YPt7XMO0dIb8IRtLe5MMNR+VNvW1tQkdLe6BVPA2i8JY0LIG7A3Opp3s0GTv75PajsQAgTTADiMc0ApKBjJSTHEj0+/VI3eqH75NM6mUutXC3nOAhA8zoGzwIdGQ4mRiESLtMlgLJwQQ4QiEqPRUMRsxUglQZCkudn0dF8FIg1NhktZefUwhRFZ49RdxTn50dBCOLwQQvPyo6ETkciJEJpfX0QPu4c5LsPJt6k15vJr6HO0CgaFbbNrs5FESSQYJRInRCRps6uudmb4gRmRi+lIOn4oUU4yU3p22M0bhXp3Kuxo0R6Y6L37oOh1xmRr2hPsDAT/wrp8/dNCQu1bDI78GvoEL4FRUbVSDYZiaJFSkKr1rcGcEMdKcV2qdq5zMR1hSFzKcibs3uNXw4fdqbC9udE1ygQMotbrjOGll+ZsTfsnldCdvv5pMR7zed5nXYDAk19DV9Aq1G9Dt1XtokreHL6Zzx4K8x0mP83amicj0baGiMllzWqPTnefmgi6LM1mY/diqqvXqhMMHtjgDnMlWLa4+//ktemJOjabK7I35NnJHtcw+9J66076sIrlZbQKVvCUxlO6lXJqNhVPiKo8FYTvTs77Bw82S0m7tkx+taIh5bNFzXbb6PfzmNA3MuEZ7fFDPYtjfGBEqBdrEiMei040OpCnald1fYtjAhA0AaCH8DUwq72bwKVqoSiRYoimiURVsq52KGb16XdX7tY5G8t1N2kPT6BnomWjA+PVVRJVKTSNx+UphTOUd6NVtAoOCJSqUZI0GmZ792k0xDb2nm2ZZNz1Pd74QI2F3ROMjTT1H2xh4zqCThylT0WZUVeTqaWeSYr24N9YW9jsynQeY/nJidTt+wSlH4nZo8jZ5Ps962rsnWpuby9ozgGA3sRLYFE1t9WHFMHQCo0KTMJxKdtcRzaO8fFweTzTQZLp+nSgBy/diDHBZKvDLb+OeMOu6kFfQH4mn1fuhC/xFcwCDwAa8Ke3Yn2El0Bb0LcSj2Y4inJcys7hL6ZeOT00vWjFS7INoTfk9z46eQYQ8Pk1+BIvgV5hKxySVF8wGoql/lpScyZ7DiEdoaFQpUmb0FnwifWHqQpCj3A7SW7GxdfRquJ/SswCRHMRqGYb0lLQhxIUyY6zbS1lwSlPLEKS8WyMJPuMab5H4aDXlG7qQSv97hbJy4vJVp3dUMrD1mmLZ7QKu0pz2EmzErFxLLCNZTXCTpI39YfeQqtQC7ZSPRRMpDCiCiK/NjzDD8wIw7P84IzPPypGBOVHe+xAz6mJQOG3s2uxu6svtdjd1avuBZ/lRfQJWi1omyrJuAYzqmtR9DafqryY0BCeiYAqcYHtoLHe8aNSn1rGVzsd/qLAHccuI1Q0KvYDj3MDj6h6sRqzTFIMZIcmtisCOZ127JkKlHryxculhrJ8+U42uGnJ61mEthtyoS5n0SrUldTFTLEb9agibRm/xbi7zurOOGJoZZqPVXSXJ9rlZUD5r/Jr6BxaBW7nXN05VpWpWhiqT7VMW5rNnawv1tgaiPL9fGCgPkCLTrYl0hAPNY9pQ17W4Q0wVs5hjTc2JT1uu9dg9TvsrN7Vwfu7PUrOHfk1NIUXNj09IinOJKpuVOLpz3eGSBTtq8q4k7vPaM9FiXpXjbVKVxfUJvy11mqkj5ZduBCXr+v1dntlmUTVKne35tfQx2hF8YONu7cURxdt/dlNNaRtfXxPRhmE3j3aLknnoFFEvkZblDZFU7J1gCnuIL0A+LdoRZ3thEibTOaN2b5xIhiisHtSxDyTqUMIkbW76+4f1GFlolvr7kv/fbZG/a+t9g60Ir/t6na5ul3IXnKyokom7XanGfkzQPlrAOiPBSwMzYnmYihJpMxMcc+lKP6vB4Z85TUUWdtQOzG+dHiYL9dVknUuegbhdxdMnNHQaFz4z6cnTQGTiTefAkD5V/JB9A5aASsApdZdNfBSVKgGayobaix6vSdp0Y9n2LJygtR59N/JyG9b2tN/oKhoRUxg0Pvyx84sw2RcSLf+aTDLF7iyAqD78b1QBSBKysYUkURCpKzV3577euWE1H77g9pO9A9B61p/pVPJ5zMA9Cq+qLzHSHGiKEpuU7CUk6osn7s0ExTDDUkXx+9tHpvyjZ0dRwZtYPTMTfsCfIfT0cw27usOz8wtpruUO/+bX0Ov4Yvg3dHbjLTpLBS34aDGQnO/kDxiF80DLd179xzRDh/gBNGWsnHj0yN7BwfC7bF5bdLvdYUGo2JXW2PM7ovUm8XESFfsoJHUpYXYvhbFA5QmXMb3QqWy8zoZySkhBTvjEaVIYfNDg2lG/rACzewZGdeOy/lfsxo9RRq8hudC6DF5MR7/pS3prA/tKnAJikfie6GhFMcmANpJMdTGINC8mJyxCaZkqy/NJ0IOvsE5gpqqPwzpfJb0bOpWbcLf6Az5smK8o05nRf6uF8u1E+OZ21Qfyf8rfxBysKD4iMK8pBpX8WJDVTBKYZOdsVnr9z8d0He4rSYL57b3LxZyTOZH0F78loLdXLAOyaxRv2HM9+xySscG/McXKgw1z3U+NXb6tRemLRfkf/4wcHSOVeJey4/A9eK7XESv7D0KSAUO8h8/UaGvFZQrnrNeQM4fBI/OsnTnk2OnX/+F8u7P83PoSfwb5duEQiJKoyutcvYJ4uhXj23OTVhGKxvfLo5D2ZvQimxVn/XhQbiCryg9SpdAvYu2M2aDjcGDZpPFuctkafgfAAAA//8BAAD//7r9C1sAAAEAAAABGFFHw2YvXw889QABA+gAAAAA2F2gzAAAAADdZi83/r3+3QgdA8kAAgADAAIAAAAAAAAAAQAAA9j+7wAACED+vf28CB0D6ADC/9EAAAAAAAAAAAAAAC54nBzMIU7EUBRG4fPfSiCQIAo1VzxKBSwAEgwCahEER9gEK2EfKAySgCEhQVUiXheAIaQzmTS9k4484nz2yBGfoCm+rCXZMed2Q2Ik6XvTSSu2NXFv/zzYIY0d4HqhtpJGPbUqTmwf2RbOL64fnCWnheO2g1tBY2UM86s7XE8x6ooL2+PMPrjWc3R6i3dlKuUYlGOhzK4y8Be9Epeqo9NtvM4+0K4BAAD//wEAAP//mB0vogAAAAAuAC4AUgCKALwA3gDsAPwBIAFgAXQBrgHmAh4CTAKEAr4C5gMuA1gDZAN+A6AD4gQMBDoEdASuBMwFCAU2BWIFnAXIBfgGEAY6BnYGngbSBvAHDgcsBzwHSgdgAAAAAQAAAC4AjAAMAGYABwABAAAAAAAAAAAAAAAAAAQAA3icnJTbThtXFIY/B9tterqoUERu0L5MpWRMoxAl4cqUoIyKcOpxepCqSoM9PojxzMgzmJIn6HXfom+Rqz5Gn6LqdbV/L4MdRUEgBPx79jr8a61/bWCT/9igVr8L/N2cG66x3fzZ8B2+aB4Z3mC/+ZnhOg8b/xhuMGi8NdzkQaNr+BPe1f80/ClP6r8ZvstW/dDw5zyubxr+csPxr+GveMK7Ba7BM/4wXGOLwvAdNvnV8Ab3sJi1OvfYMdzga7YNN9kGekyoSJmQMcIxZMKIM2YklEQkzJgwJGGAI6RNSqWvGbGQY/TBrzERFTNiRRxT4UiJSIkpGVvEt/LKea2MQ51mdtemYkzMiTxOiclw5IzIyUg4VZyKioIXtGhR0hffgoqSgJIJKQE5M0a06HDIET3GTChxHCqSZxaRM6TinFj5nVn4zvRJyCiN1RkZA/F04pfIO+QIR4dCtquRj9YiPMTxo7w9t1y23xLo160wW8+7ZBMzVz9TdSXVzbkmONatz9vmB+GKF7hb9WedyfU9Guh/pcgnnGn+A00qE5MM57ZoE0lBkbuPY1/nkEgd+YmQHq/o8Iaezm26dGlzTI+Ql/Lt0MXxHR2OOZBHKLy4O5RijvkFx/eEsvGxE+vPYmIJv1OYuktxnKmOKYV67pkHqjVRhTefsN+hfE0dpXz62iNv6TS/THsWMzJVFGI4VS+X2iitfwNTxFS1+Nle3fttmNvuLbf4glw77NW64OQnt2B03VSD9zRzrp+AmAE5J7LokzOlRcWFeL8m5owUx4G690pbUtG+9PF5LqSShKkYhGSKM6PQ39h0Exn3/prunb0lA/l7pqeXVd0mi1Ovrmb0Rt1b3kXW5WRlAi2bar6ipr64Zqb9RDu1yj+Sb6nXLecRoeIudvtDr8AOz9llj7Gy9HUzv7zzr4S32FMHTklkNZSmfQ2PCdgl4Cm77PKcp+/1csnGGR+3xmc1f5sD9umwd201C9sO+7xci/bxzH+J7Y7qcTy6PD279TQf3EC132jfrt7NribnpzG3aFfbcUzM1HNxW6s1ufsE/wMAAP//AQAA//9yoVFAAAAAAwAA//UAAP/OADIAAAAAAAAAAAAAAAAAAAAAAAAAAA==&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-2166466768 .fill-N1{fill:#0A0F25;}
		.d2-2166466768 .fill-N2{fill:#676C7E;}
		.d2-2166466768 .fill-N3{fill:#9499AB;}
		.d2-2166466768 .fill-N4{fill:#CFD2DD;}
		.d2-2166466768 .fill-N5{fill:#DEE1EB;}
		.d2-2166466768 .fill-N6{fill:#EEF1F8;}
		.d2-2166466768 .fill-N7{fill:#FFFFFF;}
		.d2-2166466768 .fill-B1{fill:#0D32B2;}
		.d2-2166466768 .fill-B2{fill:#0D32B2;}
		.d2-2166466768 .fill-B3{fill:#E3E9FD;}
		.d2-2166466768 .fill-B4{fill:#E3E9FD;}
		.d2-2166466768 .fill-B5{fill:#EDF0FD;}
		.d2-2166466768 .fill-B6{fill:#F7F8FE;}
		.d2-2166466768 .fill-AA2{fill:#4A6FF3;}
		.d2-2166466768 .fill-AA4{fill:#EDF0FD;}
		.d2-2166466768 .fill-AA5{fill:#F7F8FE;}
		.d2-2166466768 .fill-AB4{fill:#EDF0FD;}
		.d2-2166466768 .fill-AB5{fill:#F7F8FE;}
		.d2-2166466768 .stroke-N1{stroke:#0A0F25;}
		.d2-2166466768 .stroke-N2{stroke:#676C7E;}
		.d2-2166466768 .stroke-N3{stroke:#9499AB;}
		.d2-2166466768 .stroke-N4{stroke:#CFD2DD;}
		.d2-2166466768 .stroke-N5{stroke:#DEE1EB;}
		.d2-2166466768 .stroke-N6{stroke:#EEF1F8;}
		.d2-2166466768 .stroke-N7{stroke:#FFFFFF;}
		.d2-2166466768 .stroke-B1{stroke:#0D32B2;}
		.d2-2166466768 .stroke-B2{stroke:#0D32B2;}
		.d2-2166466768 .stroke-B3{stroke:#E3E9FD;}
		.d2-2166466768 .stroke-B4{stroke:#E3E9FD;}
		.d2-2166466768 .stroke-B5{stroke:#EDF0FD;}
		.d2-2166466768 .stroke-B6{stroke:#F7F8FE;}
		.d2-2166466768 .stroke-AA2{stroke:#4A6FF3;}
		.d2-2166466768 .stroke-AA4{stroke:#EDF0FD;}
		.d2-2166466768 .stroke-AA5{stroke:#F7F8FE;}
		.d2-2166466768 .stroke-AB4{stroke:#EDF0FD;}
		.d2-2166466768 .stroke-AB5{stroke:#F7F8FE;}
		.d2-2166466768 .background-color-N1{background-color:#0A0F25;}
		.d2-2166466768 .background-color-N2{background-color:#676C7E;}
		.d2-2166466768 .background-color-N3{background-color:#9499AB;}
		.d2-2166466768 .background-color-N4{background-color:#CFD2DD;}
		.d2-2166466768 .background-color-N5{background-color:#DEE1EB;}
		.d2-2166466768 .background-color-N6{background-color:#EEF1F8;}
		.d2-2166466768 .background-color-N7{background-color:#FFFFFF;}
		.d2-2166466768 .background-color-B1{background-color:#0D32B2;}
		.d2-2166466768 .background-color-B2{background-color:#0D32B2;}
		.d2-2166466768 .background-color-B3{background-color:#E3E9FD;}
		.d2-2166466768 .background-color-B4{background-color:#E3E9FD;}
		.d2-2166466768 .background-color-B5{background-color:#EDF0FD;}
		.d2-2166466768 .background-color-B6{background-color:#F7F8FE;}
		.d2-2166466768 .background-color-AA2{background-color:#4A6FF3;}
		.d2-2166466768 .background-color-AA4{background-color:#EDF0FD;}
		.d2-2166466768 .background-color-AA5{background-color:#F7F8FE;}
		.d2-2166466768 .background-color-AB4{background-color:#EDF0FD;}
		.d2-2166466768 .background-color-AB5{background-color:#F7F8FE;}
		.d2-2166466768 .color-N1{color:#0A0F25;}
		.d2-2166466768 .color-N2{color:#676C7E;}
		.d2-2166466768 .color-N3{color:#9499AB;}
		.d2-2166466768 .color-N4{color:#CFD2DD;}
		.d2-2166466768 .color-N5{color:#DEE1EB;}
		.d2-2166466768 .color-N6{color:#EEF1F8;}
		.d2-2166466768 .color-N7{color:#FFFFFF;}
		.d2-2166466768 .color-B1{color:#0D32B2;}
		.d2-2166466768 .color-B2{color:#0D32B2;}
		.d2-2166466768 .color-B3{color:#E3E9FD;}
		.d2-2166466768 .color-B4{color:#E3E9FD;}
		.d2-2166466768 .color-B5{color:#EDF0FD;}
		.d2-2166466768 .color-B6{color:#F7F8FE;}
		.d2-2166466768 .color-AA2{color:#4A6FF3;}
		.d2-2166466768 .color-AA4{color:#EDF0FD;}
		.d2-2166466768 .color-AA5{color:#F7F8FE;}
		.d2-2166466768 .color-AB4{color:#EDF0FD;}
		.d2-2166466768 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-2166466768);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-2166466768);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-2166466768);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-2166466768);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-2166466768);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-2166466768);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-2166466768);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-2166466768);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-2166466768);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-2166466768);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-2166466768);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-2166466768);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-2166466768);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-2166466768);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-2166466768);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-2166466768);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-2166466768);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-2166466768);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;Qw==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;12.000000&quot; y=&quot;68.000000&quot; width=&quot;158.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;91.000000&quot; y=&quot;106.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Client (psql, app)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;UE0=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;241.000000&quot; y=&quot;68.000000&quot; width=&quot;167.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;324.500000&quot; y=&quot;106.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;postmaster (PID 1)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Qg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;448.000000&quot; y=&quot;68.000000&quot; width=&quot;213.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;554.500000&quot; y=&quot;106.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Backend process (forked)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;U0hN&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;710.000000&quot; y=&quot;52.000000&quot; width=&quot;180.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;800.000000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;800.000000&quot; dy=&quot;0.000000&quot;&gt;Shared memory&lt;/tspan&gt;&lt;tspan x=&quot;800.000000&quot; dy=&quot;18.500000&quot;&gt;(buffers, locks, WAL)&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEMgLS0gKVswXQ==&quot;&gt;&lt;path d=&quot;M 91.000000 136.000000 L 91.000000 1063.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-2166466768)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KFBNIC0tIClbMF0=&quot;&gt;&lt;path d=&quot;M 324.500000 136.000000 L 324.500000 1063.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-2166466768)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLS0gKVswXQ==&quot;&gt;&lt;path d=&quot;M 554.500000 136.000000 L 554.500000 1063.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-2166466768)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KFNITSAtLSApWzBd&quot;&gt;&lt;path d=&quot;M 800.000000 136.000000 L 800.000000 1063.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-2166466768)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEMgLSZndDsgUE0pWzBd&quot;&gt;&lt;marker id=&quot;mk-d2-2166466768-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 93.000000 214.000000 L 320.500000 214.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-2166466768-3488378134)&quot; mask=&quot;url(#d2-2166466768)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;208.000000&quot; y=&quot;220.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;TCP connect on 5432&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFBNIC0mZ3Q7IFBNKVswXQ==&quot;&gt;&lt;path d=&quot;M 326.500000 294.000000 L 411.000000 294.000000 S 421.000000 294.000000 421.000000 304.000000 L 421.000000 329.000000 S 421.000000 339.000000 411.000000 339.000000 L 328.500000 339.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-2166466768-3488378134)&quot; mask=&quot;url(#d2-2166466768)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;421.500000&quot; y=&quot;322.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;authenticate, allocate slot&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFBNIC0mZ3Q7IEIpWzBd&quot;&gt;&lt;path d=&quot;M 326.500000 419.000000 L 550.500000 419.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-2166466768-3488378134)&quot; mask=&quot;url(#d2-2166466768)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;440.000000&quot; y=&quot;425.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;fork() new backend&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgU0hNKVswXQ==&quot;&gt;&lt;path d=&quot;M 556.500000 509.000000 L 796.000000 509.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-2166466768-3488378134)&quot; mask=&quot;url(#d2-2166466768)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;677.500000&quot; y=&quot;515.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;attach to shared memory&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFBNIC0mZ3Q7IEMpWzBd&quot;&gt;&lt;path d=&quot;M 322.500000 599.000000 L 95.000000 599.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-2166466768-3488378134)&quot; mask=&quot;url(#d2-2166466768)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;207.500000&quot; y=&quot;605.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;redirect socket to backend&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEMgLSZndDsgQilbMF0=&quot;&gt;&lt;path d=&quot;M 93.000000 689.000000 L 550.500000 689.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-2166466768-3488378134)&quot; mask=&quot;url(#d2-2166466768)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;323.000000&quot; y=&quot;695.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;queries (libpq protocol)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgU0hNKVsxXQ==&quot;&gt;&lt;path d=&quot;M 556.500000 779.000000 L 796.000000 779.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-2166466768-3488378134)&quot; mask=&quot;url(#d2-2166466768)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;677.000000&quot; y=&quot;785.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;read/write pages, take locks&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEMgLSZndDsgQilbMV0=&quot;&gt;&lt;path d=&quot;M 93.000000 869.000000 L 550.500000 869.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-2166466768-3488378134)&quot; mask=&quot;url(#d2-2166466768)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;323.000000&quot; y=&quot;875.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;disconnect&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgQilbMF0=&quot;&gt;&lt;path d=&quot;M 556.500000 949.000000 L 624.500000 949.000000 S 634.500000 949.000000 634.500000 959.000000 L 634.500000 984.000000 S 634.500000 994.000000 624.500000 994.000000 L 558.500000 994.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-2166466768-3488378134)&quot; mask=&quot;url(#d2-2166466768)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;634.500000&quot; y=&quot;977.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;process exits&lt;/text&gt;&lt;/g&gt;&lt;mask id=&quot;d2-2166466768&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-13&quot; y=&quot;27&quot; width=&quot;928&quot; height=&quot;1062&quot;&gt;
&lt;rect x=&quot;-13&quot; y=&quot;27&quot; width=&quot;928&quot; height=&quot;1062&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;139.000000&quot; y=&quot;204.000000&quot; width=&quot;138&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;333.000000&quot; y=&quot;306.000000&quot; width=&quot;177&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;375.000000&quot; y=&quot;409.000000&quot; width=&quot;130&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;592.000000&quot; y=&quot;499.000000&quot; width=&quot;171&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;119.000000&quot; y=&quot;589.000000&quot; width=&quot;177&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;245.000000&quot; y=&quot;679.000000&quot; width=&quot;156&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;582.000000&quot; y=&quot;769.000000&quot; width=&quot;190&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;285.000000&quot; y=&quot;859.000000&quot; width=&quot;76&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;590.000000&quot; y=&quot;961.000000&quot; width=&quot;89&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;A backend uses &lt;strong&gt;roughly 5–15 MB of resident memory&lt;/strong&gt; on its own, depending on Postgres version and what the connection has done (cached plan trees, prepared statements, large &lt;code&gt;work_mem&lt;/code&gt; for sorts). Multiply by &lt;code&gt;max_connections&lt;/code&gt;, add &lt;code&gt;shared_buffers&lt;/code&gt;, and you have a hard ceiling on how many backends a box can hold before you swap.&lt;/p&gt;
&lt;h3 id=&quot;why-this-matters&quot;&gt;Why this matters&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Spawning isn’t free.&lt;/strong&gt; Forking takes single-digit milliseconds. Most short-lived clients (HTTP request handlers, lambdas, CLI scripts) spend more time on connection setup than on the actual query if they reconnect every time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Idle backends still cost RAM.&lt;/strong&gt; A connection holding open a transaction overnight still pins memory and prevents &lt;code&gt;max_connections&lt;/code&gt; from being available to someone else.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;There’s no in-process query cache.&lt;/strong&gt; Each backend builds its own plan cache. Two clients running the same query don’t share a parsed plan unless they’re behind a connection pool that shares backends.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Killing a backend is the unit of cancellation.&lt;/strong&gt; &lt;code&gt;pg_terminate_backend(pid)&lt;/code&gt; sends &lt;code&gt;SIGTERM&lt;/code&gt;; &lt;code&gt;pg_cancel_backend(pid)&lt;/code&gt; cancels the &lt;em&gt;current&lt;/em&gt; query but keeps the session.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is unusual. MySQL InnoDB uses &lt;strong&gt;thread-per-connection&lt;/strong&gt; (one OS thread, shared address space — lower memory per connection, but a bug in one thread’s code path can corrupt another’s state). MS SQL Server uses &lt;strong&gt;fiber-style scheduling&lt;/strong&gt; on a thread pool. Postgres’s choice was made in the early 1990s for isolation and portability, and it has shaped almost every operational pattern around the database since.&lt;/p&gt;
&lt;p&gt;The practical consequence: &lt;strong&gt;&lt;code&gt;max_connections&lt;/code&gt; caps the number of &lt;em&gt;backends&lt;/em&gt;, not the number of &lt;em&gt;clients you can serve&lt;/em&gt;.&lt;/strong&gt; Each backend is a process tied to one CPU core at a time, so useful work is bounded by your cores — not by how many backends you allow. But most clients spend most of their time &lt;em&gt;not&lt;/em&gt; executing a query: they’re waiting on the network, on application code, on a user clicking a button. A small pool of backends, kept busy and shared across many clients, serves far more clients than the pool’s size. That gap — many clients, few backends — is the gap connection pooling exists to close.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;2-the-vocabulary&quot;&gt;2. The Vocabulary&lt;/h2&gt;
&lt;p&gt;Before any code, the words. Concurrency discussions go sideways quickly when these terms are used loosely.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Backend&lt;/strong&gt; — the OS process that serves one client connection. One backend per connection, period. Visible in &lt;code&gt;ps&lt;/code&gt; as &lt;code&gt;postgres: user dbname host(port) idle&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;postmaster&lt;/code&gt;&lt;/strong&gt; — the parent supervisor process. Accepts connections, forks backends, restarts crashed background workers. PID 1 of the cluster.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;max_connections&lt;/code&gt;&lt;/strong&gt; — hard upper bound on simultaneous backends. Changing it requires a restart. Default 100. Includes superuser-reserved slots.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Connection pool&lt;/strong&gt; — a layer between clients and the database that maintains a small pool of long-lived backends and multiplexes many client connections over them. Implementations: PgBouncer, pgcat, Supabase Supavisor, application-side pools (HikariCP, &lt;code&gt;pgx&lt;/code&gt;’s built-in pool).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pool mode&lt;/strong&gt; — how aggressively the pooler hands out backends. &lt;strong&gt;Session&lt;/strong&gt; = backend held for the whole client session; &lt;strong&gt;Transaction&lt;/strong&gt; = backend assigned per transaction; &lt;strong&gt;Statement&lt;/strong&gt; = backend per statement (rarely used).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Heavyweight lock&lt;/strong&gt; (or &lt;em&gt;regular lock&lt;/em&gt;) — a lock on a database object (a table, a row, an index, an advisory key) that Postgres takes on your behalf when you run a statement. You don’t pick the mode; the statement does. Tracked in the cluster-wide lock table, visible in &lt;code&gt;pg_locks&lt;/code&gt;, released at transaction end.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lightweight lock (LWLock)&lt;/strong&gt; — an internal lock protecting shared-memory data structures inside Postgres (buffer pool slots, the WAL insert position, the lock table itself). Two modes: SHARED and EXCLUSIVE. Held for microseconds. You don’t take these directly — they’re acquired by Postgres internals on your behalf.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spinlock&lt;/strong&gt; — the lowest-level mutex, used when a lock is held for nanoseconds. Busy-waits in a tight loop. Below LWLocks in the stack.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lock mode&lt;/strong&gt; — for heavyweight locks, the &lt;em&gt;kind&lt;/em&gt; of lock: from the gentlest &lt;code&gt;ACCESS SHARE&lt;/code&gt; (a &lt;code&gt;SELECT&lt;/code&gt;) to &lt;code&gt;ACCESS EXCLUSIVE&lt;/code&gt; (an &lt;code&gt;ALTER TABLE&lt;/code&gt;). Eight modes total. A lock conflict matrix says which pairs of modes can coexist on the same object and which block each other.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;MVCC (Multi-Version Concurrency Control)&lt;/strong&gt; — the trick that lets Postgres readers and writers ignore each other. Instead of locking a row while you read it, Postgres keeps multiple versions of the row on disk and serves whichever version was committed when your transaction started. A long-running &lt;code&gt;SELECT&lt;/code&gt; doesn’t block &lt;code&gt;UPDATE&lt;/code&gt;s, and ongoing &lt;code&gt;UPDATE&lt;/code&gt;s don’t block readers — they each see their own consistent snapshot. The cost: outdated versions pile up until vacuum reclaims them. Postgres, Oracle, and MySQL InnoDB all use MVCC. Section 5 unpacks the on-disk mechanics.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tuple&lt;/strong&gt; — Postgres’s term for a row. Specifically, a &lt;em&gt;physical&lt;/em&gt; row version on a heap page. An &lt;code&gt;UPDATE&lt;/code&gt; produces a new tuple; the old one stays around for MVCC visibility until vacuum reclaims it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;xmin&lt;/code&gt; / &lt;code&gt;xmax&lt;/code&gt;&lt;/strong&gt; — hidden columns on every tuple. &lt;code&gt;xmin&lt;/code&gt; = the transaction ID that inserted it. &lt;code&gt;xmax&lt;/code&gt; = the transaction ID that deleted or updated it (zero if neither). Together they decide whether a tuple is visible to a given snapshot.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;XID (Transaction ID)&lt;/strong&gt; — a 32-bit number assigned to every write transaction. Read-only transactions get a “virtual” XID that costs nothing. Wraparound is real, autovacuum manages it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Snapshot&lt;/strong&gt; — a frozen record of “which transactions had already committed at the moment I started.” Every transaction takes one. Every row the transaction reads is filtered through it, so the transaction sees a consistent point-in-time view of the database even as other transactions commit changes around it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Wait event&lt;/strong&gt; — what a backend is blocked on right now. Column in &lt;code&gt;pg_stat_activity&lt;/code&gt;. Values include &lt;code&gt;Lock&lt;/code&gt; (waiting on a heavyweight lock), &lt;code&gt;LWLock&lt;/code&gt;, &lt;code&gt;BufferPin&lt;/code&gt;, &lt;code&gt;IO&lt;/code&gt;, &lt;code&gt;Client&lt;/code&gt;, &lt;code&gt;Timeout&lt;/code&gt;, &lt;code&gt;IPC&lt;/code&gt;. The first thing to check when “the database is slow.”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Deadlock&lt;/strong&gt; — two or more transactions waiting on locks held by each other, forming a cycle. Postgres detects this periodically (every &lt;code&gt;deadlock_timeout&lt;/code&gt;, default 1 second) and aborts one transaction with &lt;code&gt;SQLSTATE 40P01&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Advisory lock&lt;/strong&gt; — a database-hosted mutex that callers compete for using an integer key they pick themselves. Postgres doesn’t connect the key to any row, table, or object — it just guarantees that two callers asking for the same key can’t both hold the lock at once. Used by application code to serialize work across processes (“only one instance runs this cron job,” “elect a leader”) when you already have a database and don’t want to stand up a separate coordinator like Redis or ZooKeeper.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;3-connection-pooling&quot;&gt;3. Connection Pooling&lt;/h2&gt;
&lt;p&gt;A backend can run one query at a time, and the OS can only execute as many processes in parallel as the box has cores. So however many backends you allow, only a handful are &lt;em&gt;actually doing work&lt;/em&gt; in any given moment — roughly &lt;code&gt;2 × cores + effective_io_concurrency&lt;/code&gt;, give or take, depending on how much your queries wait on disk. Stack more backends on top of that and they start fighting each other for the same CPU and the same internal lock table; throughput stops climbing and starts dropping:&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 557 716&quot;&gt;&lt;svg class=&quot;d2-918885922 d2-svg&quot; width=&quot;557&quot; height=&quot;716&quot; viewBox=&quot;-13 27 557 716&quot;&gt;&lt;rect x=&quot;-13.000000&quot; y=&quot;27.000000&quot; width=&quot;557.000000&quot; height=&quot;716.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-918885922 .text {
	font-family: &quot;d2-918885922-font-regular&quot;;
}
@font-face {
	font-family: d2-918885922-font-regular;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-918885922 .text-italic {
	font-family: &quot;d2-918885922-font-italic&quot;;
}
@font-face {
	font-family: d2-918885922-font-italic;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-918885922 .fill-N1{fill:#0A0F25;}
		.d2-918885922 .fill-N2{fill:#676C7E;}
		.d2-918885922 .fill-N3{fill:#9499AB;}
		.d2-918885922 .fill-N4{fill:#CFD2DD;}
		.d2-918885922 .fill-N5{fill:#DEE1EB;}
		.d2-918885922 .fill-N6{fill:#EEF1F8;}
		.d2-918885922 .fill-N7{fill:#FFFFFF;}
		.d2-918885922 .fill-B1{fill:#0D32B2;}
		.d2-918885922 .fill-B2{fill:#0D32B2;}
		.d2-918885922 .fill-B3{fill:#E3E9FD;}
		.d2-918885922 .fill-B4{fill:#E3E9FD;}
		.d2-918885922 .fill-B5{fill:#EDF0FD;}
		.d2-918885922 .fill-B6{fill:#F7F8FE;}
		.d2-918885922 .fill-AA2{fill:#4A6FF3;}
		.d2-918885922 .fill-AA4{fill:#EDF0FD;}
		.d2-918885922 .fill-AA5{fill:#F7F8FE;}
		.d2-918885922 .fill-AB4{fill:#EDF0FD;}
		.d2-918885922 .fill-AB5{fill:#F7F8FE;}
		.d2-918885922 .stroke-N1{stroke:#0A0F25;}
		.d2-918885922 .stroke-N2{stroke:#676C7E;}
		.d2-918885922 .stroke-N3{stroke:#9499AB;}
		.d2-918885922 .stroke-N4{stroke:#CFD2DD;}
		.d2-918885922 .stroke-N5{stroke:#DEE1EB;}
		.d2-918885922 .stroke-N6{stroke:#EEF1F8;}
		.d2-918885922 .stroke-N7{stroke:#FFFFFF;}
		.d2-918885922 .stroke-B1{stroke:#0D32B2;}
		.d2-918885922 .stroke-B2{stroke:#0D32B2;}
		.d2-918885922 .stroke-B3{stroke:#E3E9FD;}
		.d2-918885922 .stroke-B4{stroke:#E3E9FD;}
		.d2-918885922 .stroke-B5{stroke:#EDF0FD;}
		.d2-918885922 .stroke-B6{stroke:#F7F8FE;}
		.d2-918885922 .stroke-AA2{stroke:#4A6FF3;}
		.d2-918885922 .stroke-AA4{stroke:#EDF0FD;}
		.d2-918885922 .stroke-AA5{stroke:#F7F8FE;}
		.d2-918885922 .stroke-AB4{stroke:#EDF0FD;}
		.d2-918885922 .stroke-AB5{stroke:#F7F8FE;}
		.d2-918885922 .background-color-N1{background-color:#0A0F25;}
		.d2-918885922 .background-color-N2{background-color:#676C7E;}
		.d2-918885922 .background-color-N3{background-color:#9499AB;}
		.d2-918885922 .background-color-N4{background-color:#CFD2DD;}
		.d2-918885922 .background-color-N5{background-color:#DEE1EB;}
		.d2-918885922 .background-color-N6{background-color:#EEF1F8;}
		.d2-918885922 .background-color-N7{background-color:#FFFFFF;}
		.d2-918885922 .background-color-B1{background-color:#0D32B2;}
		.d2-918885922 .background-color-B2{background-color:#0D32B2;}
		.d2-918885922 .background-color-B3{background-color:#E3E9FD;}
		.d2-918885922 .background-color-B4{background-color:#E3E9FD;}
		.d2-918885922 .background-color-B5{background-color:#EDF0FD;}
		.d2-918885922 .background-color-B6{background-color:#F7F8FE;}
		.d2-918885922 .background-color-AA2{background-color:#4A6FF3;}
		.d2-918885922 .background-color-AA4{background-color:#EDF0FD;}
		.d2-918885922 .background-color-AA5{background-color:#F7F8FE;}
		.d2-918885922 .background-color-AB4{background-color:#EDF0FD;}
		.d2-918885922 .background-color-AB5{background-color:#F7F8FE;}
		.d2-918885922 .color-N1{color:#0A0F25;}
		.d2-918885922 .color-N2{color:#676C7E;}
		.d2-918885922 .color-N3{color:#9499AB;}
		.d2-918885922 .color-N4{color:#CFD2DD;}
		.d2-918885922 .color-N5{color:#DEE1EB;}
		.d2-918885922 .color-N6{color:#EEF1F8;}
		.d2-918885922 .color-N7{color:#FFFFFF;}
		.d2-918885922 .color-B1{color:#0D32B2;}
		.d2-918885922 .color-B2{color:#0D32B2;}
		.d2-918885922 .color-B3{color:#E3E9FD;}
		.d2-918885922 .color-B4{color:#E3E9FD;}
		.d2-918885922 .color-B5{color:#EDF0FD;}
		.d2-918885922 .color-B6{color:#F7F8FE;}
		.d2-918885922 .color-AA2{color:#4A6FF3;}
		.d2-918885922 .color-AA4{color:#EDF0FD;}
		.d2-918885922 .color-AA5{color:#F7F8FE;}
		.d2-918885922 .color-AB4{color:#EDF0FD;}
		.d2-918885922 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-918885922);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-918885922);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-918885922);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-918885922);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-918885922);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-918885922);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-918885922);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-918885922);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-918885922);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-918885922);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-918885922);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-918885922);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-918885922);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-918885922);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-918885922);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-918885922);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-918885922);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-918885922);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;WA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;12.000000&quot; y=&quot;52.000000&quot; width=&quot;154.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;89.000000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Active backends&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;VA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;393.000000&quot; y=&quot;52.000000&quot; width=&quot;126.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;456.000000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Throughput&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFggLS0gKVswXQ==&quot;&gt;&lt;path d=&quot;M 89.000000 120.000000 L 89.000000 717.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-918885922)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KFQgLS0gKVswXQ==&quot;&gt;&lt;path d=&quot;M 456.000000 120.000000 L 456.000000 717.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-918885922)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KFggLSZndDsgVClbMF0=&quot;&gt;&lt;marker id=&quot;mk-d2-918885922-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 91.000000 198.000000 L 452.000000 198.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-918885922-3488378134)&quot; mask=&quot;url(#d2-918885922)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;272.500000&quot; y=&quot;204.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;1 backend → 100 qps&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFggLSZndDsgVClbMV0=&quot;&gt;&lt;path d=&quot;M 91.000000 288.000000 L 452.000000 288.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-918885922-3488378134)&quot; mask=&quot;url(#d2-918885922)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;272.500000&quot; y=&quot;294.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;10 backends → 800 qps&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFggLSZndDsgVClbMl0=&quot;&gt;&lt;path d=&quot;M 91.000000 378.000000 L 452.000000 378.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-918885922-3488378134)&quot; mask=&quot;url(#d2-918885922)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;273.000000&quot; y=&quot;384.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;40 backends → 1200 qps (peak)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFggLSZndDsgVClbM10=&quot;&gt;&lt;path d=&quot;M 91.000000 468.000000 L 452.000000 468.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-918885922-3488378134)&quot; mask=&quot;url(#d2-918885922)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;272.500000&quot; y=&quot;474.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;100 backends → 1100 qps (CPU contention)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFggLSZndDsgVClbNF0=&quot;&gt;&lt;path d=&quot;M 91.000000 558.000000 L 452.000000 558.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-918885922-3488378134)&quot; mask=&quot;url(#d2-918885922)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;272.500000&quot; y=&quot;564.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;400 backends → 600 qps (lock-table contention)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFggLSZndDsgVClbNV0=&quot;&gt;&lt;path d=&quot;M 91.000000 648.000000 L 452.000000 648.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-918885922-3488378134)&quot; mask=&quot;url(#d2-918885922)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;273.000000&quot; y=&quot;654.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;1000 backends → 200 qps + OOM risk&lt;/text&gt;&lt;/g&gt;&lt;mask id=&quot;d2-918885922&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-13&quot; y=&quot;27&quot; width=&quot;557&quot; height=&quot;716&quot;&gt;
&lt;rect x=&quot;-13&quot; y=&quot;27&quot; width=&quot;557&quot; height=&quot;716&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;203.000000&quot; y=&quot;188.000000&quot; width=&quot;139&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;196.000000&quot; y=&quot;278.000000&quot; width=&quot;153&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;171.000000&quot; y=&quot;368.000000&quot; width=&quot;204&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;132.000000&quot; y=&quot;458.000000&quot; width=&quot;281&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;117.000000&quot; y=&quot;548.000000&quot; width=&quot;311&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;153.000000&quot; y=&quot;638.000000&quot; width=&quot;240&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;The trick: most applications have thousands of &lt;em&gt;clients&lt;/em&gt; but only need dozens of &lt;em&gt;backends&lt;/em&gt; at any instant. A web server with 200 worker threads doesn’t issue 200 simultaneous queries — most threads spend most of their time in application logic, I/O to other services, or idle. A connection pooler exploits this.&lt;/p&gt;
&lt;h3 id=&quot;pgbouncer-pool-modes&quot;&gt;PgBouncer pool modes&lt;/h3&gt;
&lt;p&gt;PgBouncer is the industry-standard Postgres pooler. Its three modes differ in how long it holds a backend on behalf of a client.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Session pooling.&lt;/strong&gt; A client connects, PgBouncer assigns it a backend, the backend stays bound to that client until the client disconnects. PgBouncer is essentially a connection multiplexer for the &lt;em&gt;count&lt;/em&gt;, not the &lt;em&gt;time&lt;/em&gt;. Useful when you have many &lt;em&gt;short-lived&lt;/em&gt; clients (CLI scripts, lambdas) but ordinary session semantics inside each one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Transaction pooling.&lt;/strong&gt; A client checks out a backend at &lt;code&gt;BEGIN&lt;/code&gt; and returns it at &lt;code&gt;COMMIT&lt;/code&gt;/&lt;code&gt;ROLLBACK&lt;/code&gt;. Between transactions, the same backend can serve a different client. This is the high-leverage mode — a pool of 50 backends easily serves 5000 clients if average transactions are a few milliseconds. &lt;strong&gt;Most production deployments use transaction pooling.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Statement pooling.&lt;/strong&gt; Backend returned after every statement. Breaks multi-statement transactions entirely. Rarely useful outside read-only pipelines.&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 971 1256&quot;&gt;&lt;svg class=&quot;d2-116078550 d2-svg&quot; width=&quot;971&quot; height=&quot;1256&quot; viewBox=&quot;-13 27 971 1256&quot;&gt;&lt;rect x=&quot;-13.000000&quot; y=&quot;27.000000&quot; width=&quot;971.000000&quot; height=&quot;1256.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-116078550 .text {
	font-family: &quot;d2-116078550-font-regular&quot;;
}
@font-face {
	font-family: d2-116078550-font-regular;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-116078550 .text-italic {
	font-family: &quot;d2-116078550-font-italic&quot;;
}
@font-face {
	font-family: d2-116078550-font-italic;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-116078550 .fill-N1{fill:#0A0F25;}
		.d2-116078550 .fill-N2{fill:#676C7E;}
		.d2-116078550 .fill-N3{fill:#9499AB;}
		.d2-116078550 .fill-N4{fill:#CFD2DD;}
		.d2-116078550 .fill-N5{fill:#DEE1EB;}
		.d2-116078550 .fill-N6{fill:#EEF1F8;}
		.d2-116078550 .fill-N7{fill:#FFFFFF;}
		.d2-116078550 .fill-B1{fill:#0D32B2;}
		.d2-116078550 .fill-B2{fill:#0D32B2;}
		.d2-116078550 .fill-B3{fill:#E3E9FD;}
		.d2-116078550 .fill-B4{fill:#E3E9FD;}
		.d2-116078550 .fill-B5{fill:#EDF0FD;}
		.d2-116078550 .fill-B6{fill:#F7F8FE;}
		.d2-116078550 .fill-AA2{fill:#4A6FF3;}
		.d2-116078550 .fill-AA4{fill:#EDF0FD;}
		.d2-116078550 .fill-AA5{fill:#F7F8FE;}
		.d2-116078550 .fill-AB4{fill:#EDF0FD;}
		.d2-116078550 .fill-AB5{fill:#F7F8FE;}
		.d2-116078550 .stroke-N1{stroke:#0A0F25;}
		.d2-116078550 .stroke-N2{stroke:#676C7E;}
		.d2-116078550 .stroke-N3{stroke:#9499AB;}
		.d2-116078550 .stroke-N4{stroke:#CFD2DD;}
		.d2-116078550 .stroke-N5{stroke:#DEE1EB;}
		.d2-116078550 .stroke-N6{stroke:#EEF1F8;}
		.d2-116078550 .stroke-N7{stroke:#FFFFFF;}
		.d2-116078550 .stroke-B1{stroke:#0D32B2;}
		.d2-116078550 .stroke-B2{stroke:#0D32B2;}
		.d2-116078550 .stroke-B3{stroke:#E3E9FD;}
		.d2-116078550 .stroke-B4{stroke:#E3E9FD;}
		.d2-116078550 .stroke-B5{stroke:#EDF0FD;}
		.d2-116078550 .stroke-B6{stroke:#F7F8FE;}
		.d2-116078550 .stroke-AA2{stroke:#4A6FF3;}
		.d2-116078550 .stroke-AA4{stroke:#EDF0FD;}
		.d2-116078550 .stroke-AA5{stroke:#F7F8FE;}
		.d2-116078550 .stroke-AB4{stroke:#EDF0FD;}
		.d2-116078550 .stroke-AB5{stroke:#F7F8FE;}
		.d2-116078550 .background-color-N1{background-color:#0A0F25;}
		.d2-116078550 .background-color-N2{background-color:#676C7E;}
		.d2-116078550 .background-color-N3{background-color:#9499AB;}
		.d2-116078550 .background-color-N4{background-color:#CFD2DD;}
		.d2-116078550 .background-color-N5{background-color:#DEE1EB;}
		.d2-116078550 .background-color-N6{background-color:#EEF1F8;}
		.d2-116078550 .background-color-N7{background-color:#FFFFFF;}
		.d2-116078550 .background-color-B1{background-color:#0D32B2;}
		.d2-116078550 .background-color-B2{background-color:#0D32B2;}
		.d2-116078550 .background-color-B3{background-color:#E3E9FD;}
		.d2-116078550 .background-color-B4{background-color:#E3E9FD;}
		.d2-116078550 .background-color-B5{background-color:#EDF0FD;}
		.d2-116078550 .background-color-B6{background-color:#F7F8FE;}
		.d2-116078550 .background-color-AA2{background-color:#4A6FF3;}
		.d2-116078550 .background-color-AA4{background-color:#EDF0FD;}
		.d2-116078550 .background-color-AA5{background-color:#F7F8FE;}
		.d2-116078550 .background-color-AB4{background-color:#EDF0FD;}
		.d2-116078550 .background-color-AB5{background-color:#F7F8FE;}
		.d2-116078550 .color-N1{color:#0A0F25;}
		.d2-116078550 .color-N2{color:#676C7E;}
		.d2-116078550 .color-N3{color:#9499AB;}
		.d2-116078550 .color-N4{color:#CFD2DD;}
		.d2-116078550 .color-N5{color:#DEE1EB;}
		.d2-116078550 .color-N6{color:#EEF1F8;}
		.d2-116078550 .color-N7{color:#FFFFFF;}
		.d2-116078550 .color-B1{color:#0D32B2;}
		.d2-116078550 .color-B2{color:#0D32B2;}
		.d2-116078550 .color-B3{color:#E3E9FD;}
		.d2-116078550 .color-B4{color:#E3E9FD;}
		.d2-116078550 .color-B5{color:#EDF0FD;}
		.d2-116078550 .color-B6{color:#F7F8FE;}
		.d2-116078550 .color-AA2{color:#4A6FF3;}
		.d2-116078550 .color-AA4{color:#EDF0FD;}
		.d2-116078550 .color-AA5{color:#F7F8FE;}
		.d2-116078550 .color-AB4{color:#EDF0FD;}
		.d2-116078550 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-116078550);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-116078550);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-116078550);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-116078550);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-116078550);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-116078550);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-116078550);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-116078550);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-116078550);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-116078550);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-116078550);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-116078550);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-116078550);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-116078550);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-116078550);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-116078550);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-116078550);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-116078550);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;QzE=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;12.000000&quot; y=&quot;52.000000&quot; width=&quot;100.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;62.000000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Client A&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;QzI=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;162.000000&quot; y=&quot;52.000000&quot; width=&quot;100.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;212.000000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Client B&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;UA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;302.000000&quot; y=&quot;52.000000&quot; width=&quot;323.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;463.500000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;PgBouncer (transaction pool, 2 backends)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;QjE=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;665.000000&quot; y=&quot;52.000000&quot; width=&quot;114.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;722.000000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Backend 1&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;QjI=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;819.000000&quot; y=&quot;52.000000&quot; width=&quot;114.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;876.000000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Backend 2&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEMxIC0tIClbMF0=&quot;&gt;&lt;path d=&quot;M 62.000000 120.000000 L 62.000000 1257.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-116078550)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEMyIC0tIClbMF0=&quot;&gt;&lt;path d=&quot;M 212.000000 120.000000 L 212.000000 1257.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-116078550)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KFAgLS0gKVswXQ==&quot;&gt;&lt;path d=&quot;M 463.500000 120.000000 L 463.500000 1257.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-116078550)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEIxIC0tIClbMF0=&quot;&gt;&lt;path d=&quot;M 722.000000 120.000000 L 722.000000 1257.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-116078550)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEIyIC0tIClbMF0=&quot;&gt;&lt;path d=&quot;M 876.000000 120.000000 L 876.000000 1257.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-116078550)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEMxIC0mZ3Q7IFApWzBd&quot;&gt;&lt;marker id=&quot;mk-d2-116078550-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 64.000000 198.000000 L 459.500000 198.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-116078550-3488378134)&quot; mask=&quot;url(#d2-116078550)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;262.500000&quot; y=&quot;204.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;BEGIN&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFAgLSZndDsgQjEpWzBd&quot;&gt;&lt;path d=&quot;M 465.500000 288.000000 L 718.000000 288.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-116078550-3488378134)&quot; mask=&quot;url(#d2-116078550)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;593.000000&quot; y=&quot;294.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;BEGIN (B1 assigned to A)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEMyIC0mZ3Q7IFApWzBd&quot;&gt;&lt;path d=&quot;M 214.000000 378.000000 L 459.500000 378.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-116078550-3488378134)&quot; mask=&quot;url(#d2-116078550)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;337.500000&quot; y=&quot;384.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;BEGIN&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFAgLSZndDsgQjIpWzBd&quot;&gt;&lt;path d=&quot;M 465.500000 468.000000 L 872.000000 468.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-116078550-3488378134)&quot; mask=&quot;url(#d2-116078550)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;669.500000&quot; y=&quot;474.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;BEGIN (B2 assigned to B)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEMxIC0mZ3Q7IFApWzFd&quot;&gt;&lt;path d=&quot;M 64.000000 558.000000 L 459.500000 558.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-116078550-3488378134)&quot; mask=&quot;url(#d2-116078550)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;262.500000&quot; y=&quot;564.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;SELECT ...&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFAgLSZndDsgQjEpWzFd&quot;&gt;&lt;path d=&quot;M 465.500000 648.000000 L 718.000000 648.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-116078550-3488378134)&quot; mask=&quot;url(#d2-116078550)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;592.500000&quot; y=&quot;654.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;forward&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEMxIC0mZ3Q7IFApWzJd&quot;&gt;&lt;path d=&quot;M 64.000000 738.000000 L 459.500000 738.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-116078550-3488378134)&quot; mask=&quot;url(#d2-116078550)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;263.000000&quot; y=&quot;744.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;COMMIT&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFAgLSZndDsgQjEpWzJd&quot;&gt;&lt;path d=&quot;M 465.500000 828.000000 L 718.000000 828.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-116078550-3488378134)&quot; mask=&quot;url(#d2-116078550)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;592.500000&quot; y=&quot;834.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;COMMIT, B1 returned to pool&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEMyIC0mZ3Q7IFApWzFd&quot;&gt;&lt;path d=&quot;M 214.000000 918.000000 L 459.500000 918.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-116078550-3488378134)&quot; mask=&quot;url(#d2-116078550)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;338.000000&quot; y=&quot;924.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;INSERT ...&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFAgLSZndDsgQjIpWzFd&quot;&gt;&lt;path d=&quot;M 465.500000 1008.000000 L 872.000000 1008.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-116078550-3488378134)&quot; mask=&quot;url(#d2-116078550)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;669.500000&quot; y=&quot;1014.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;forward&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEMxIC0mZ3Q7IFApWzNd&quot;&gt;&lt;path d=&quot;M 64.000000 1098.000000 L 459.500000 1098.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-116078550-3488378134)&quot; mask=&quot;url(#d2-116078550)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;262.500000&quot; y=&quot;1104.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;BEGIN (now reuses B1)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFAgLSZndDsgQjEpWzNd&quot;&gt;&lt;path d=&quot;M 465.500000 1188.000000 L 718.000000 1188.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-116078550-3488378134)&quot; mask=&quot;url(#d2-116078550)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;592.500000&quot; y=&quot;1194.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;BEGIN&lt;/text&gt;&lt;/g&gt;&lt;mask id=&quot;d2-116078550&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-13&quot; y=&quot;27&quot; width=&quot;971&quot; height=&quot;1256&quot;&gt;
&lt;rect x=&quot;-13&quot; y=&quot;27&quot; width=&quot;971&quot; height=&quot;1256&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;240.000000&quot; y=&quot;188.000000&quot; width=&quot;45&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;511.000000&quot; y=&quot;278.000000&quot; width=&quot;164&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;315.000000&quot; y=&quot;368.000000&quot; width=&quot;45&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;587.000000&quot; y=&quot;458.000000&quot; width=&quot;165&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;229.000000&quot; y=&quot;548.000000&quot; width=&quot;67&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;564.000000&quot; y=&quot;638.000000&quot; width=&quot;57&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;233.000000&quot; y=&quot;728.000000&quot; width=&quot;60&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;497.000000&quot; y=&quot;818.000000&quot; width=&quot;191&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;305.000000&quot; y=&quot;908.000000&quot; width=&quot;66&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;641.000000&quot; y=&quot;998.000000&quot; width=&quot;57&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;187.000000&quot; y=&quot;1088.000000&quot; width=&quot;151&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;570.000000&quot; y=&quot;1178.000000&quot; width=&quot;45&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;h3 id=&quot;transaction-pooling-caveats-the-real-world-list&quot;&gt;Transaction-pooling caveats (the real-world list)&lt;/h3&gt;
&lt;p&gt;The cost of transaction pooling is that &lt;strong&gt;anything that relies on session state between transactions breaks&lt;/strong&gt;. The exhaustive list:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Server-side prepared statements.&lt;/strong&gt; A prepared statement lives on the backend that prepared it. If the next transaction lands on a different backend, the prepared name doesn’t exist. The fixes: tell your driver to disable server-side prepares (&lt;code&gt;prepareThreshold=0&lt;/code&gt; in JDBC; &lt;code&gt;binary_parameters=yes&lt;/code&gt; + &lt;code&gt;prefer_simple_protocol&lt;/code&gt; in some Go drivers), or use a pooler that emulates prepared statements (recent PgBouncer ≥ 1.21 and pgcat both do this).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;SET&lt;/code&gt; (without &lt;code&gt;LOCAL&lt;/code&gt;).&lt;/strong&gt; Session-scoped &lt;code&gt;SET timezone = &apos;UTC&apos;&lt;/code&gt; is sticky on the backend. The next client lands on a backend with whatever the previous client did. Use &lt;code&gt;SET LOCAL&lt;/code&gt;, which is transaction-scoped and cleared at &lt;code&gt;COMMIT&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cursors declared with &lt;code&gt;DECLARE CURSOR ... WITH HOLD&lt;/code&gt;.&lt;/strong&gt; Cursors don’t survive backend hand-off. Use server-side cursors only in session pooling.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;LISTEN&lt;/code&gt; / &lt;code&gt;NOTIFY&lt;/code&gt;.&lt;/strong&gt; The subscription is on the backend. Once the backend is returned to the pool, you stop receiving notifications.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Temporary tables.&lt;/strong&gt; &lt;code&gt;CREATE TEMP TABLE&lt;/code&gt; lives on the backend; the next transaction won’t see it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Advisory session locks (&lt;code&gt;pg_advisory_lock&lt;/code&gt;).&lt;/strong&gt; Released only when the backend session ends. Under transaction pooling, sessions don’t really end on the client’s clock — use &lt;code&gt;pg_advisory_xact_lock&lt;/code&gt; instead.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When PgBouncer’s transaction pooling caveats bite, the symptom is usually “works in dev with one client, breaks in prod under load.” The fix is either to disable the offending session-scoped feature or to put PgBouncer in session-pooling mode for the specific path that needs it (two pools, two ports).&lt;/p&gt;
&lt;h3 id=&quot;pool-sizing&quot;&gt;Pool sizing&lt;/h3&gt;
&lt;p&gt;The starting formula for the backend pool:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;pool_size = (cpu_cores × 2) + effective_io_concurrency&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For a 16-core box on NVMe: &lt;code&gt;16 × 2 + 4 ≈ 36&lt;/code&gt;. Round to 40. The remaining &lt;code&gt;max_connections&lt;/code&gt; budget pays for admin sessions, replication slots, and headroom.&lt;/p&gt;
&lt;p&gt;The starting formula for the &lt;em&gt;client&lt;/em&gt; side (&lt;code&gt;default_pool_size × max_db_connections&lt;/code&gt;):&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;max_client_conn = number of app instances × average client pool size&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Set this generously — PgBouncer holds idle clients cheaply (a few KB each).&lt;/p&gt;
&lt;h3 id=&quot;whats-after-pgbouncer&quot;&gt;What’s after PgBouncer&lt;/h3&gt;
&lt;p&gt;PgBouncer is single-process, single-threaded (which is fine for hundreds of thousands of clients on modern CPUs, but caps single-instance throughput in the millions-of-qps range). The newer options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/postgresml/pgcat&quot;&gt;pgcat&lt;/a&gt;&lt;/strong&gt; — Rust, multi-threaded, supports sharding and read/write splitting natively.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Supabase Supavisor&lt;/strong&gt; — Erlang/Elixir, designed for cloud-scale fan-in.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/yandex/odyssey&quot;&gt;Odyssey&lt;/a&gt;&lt;/strong&gt; (Yandex) — multi-threaded, transaction-pooling pgbouncer drop-in.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the median application: PgBouncer in transaction-pooling mode, in front of a pool of 30–60 backends, is the right starting point.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;4-the-lock-manager&quot;&gt;4. The Lock Manager&lt;/h2&gt;
&lt;p&gt;Two layers, very different jobs.&lt;/p&gt;
&lt;h3 id=&quot;heavyweight-locks--the-user-visible-layer&quot;&gt;Heavyweight locks — the user-visible layer&lt;/h3&gt;
&lt;p&gt;Heavyweight locks protect database objects: tables, rows, indexes, advisory keys. They’re tracked in a cluster-wide hash table in shared memory, indexed by &lt;code&gt;(database, relation, object)&lt;/code&gt;. Every entry records which transaction holds it, in which mode, and which transactions are queued waiting for it.&lt;/p&gt;
&lt;p&gt;There are two questions to keep straight, and the post is going to answer them with two separate tables.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Acquisition&lt;/strong&gt; — given a SQL statement, which mode does it take?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compatibility&lt;/strong&gt; — given two locks on the same object, can they coexist or does one wait?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first is a one-way lookup. The second is a symmetric relation between every pair of modes, and it’s the actual conflict matrix Postgres consults on every request.&lt;/p&gt;
&lt;h3 id=&quot;acquisition-which-statement-takes-which-mode&quot;&gt;Acquisition: which statement takes which mode&lt;/h3&gt;
&lt;p&gt;Postgres defines &lt;strong&gt;eight table-level lock modes&lt;/strong&gt;. Statements take whichever they need automatically, weakest to strongest:&lt;/p&gt;









































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Mode&lt;/th&gt;&lt;th&gt;Acquired by&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;ACCESS SHARE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;SELECT&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;ROW SHARE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;SELECT FOR UPDATE / FOR SHARE&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;ROW EXCLUSIVE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;INSERT&lt;/code&gt;, &lt;code&gt;UPDATE&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;SHARE UPDATE EXCLUSIVE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;VACUUM&lt;/code&gt; (non-FULL), &lt;code&gt;ANALYZE&lt;/code&gt;, &lt;code&gt;CREATE INDEX CONCURRENTLY&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;SHARE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;CREATE INDEX&lt;/code&gt; (non-concurrent)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;SHARE ROW EXCLUSIVE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;rarely explicit&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;EXCLUSIVE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;REFRESH MATERIALIZED VIEW CONCURRENTLY&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;ACCESS EXCLUSIVE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;ALTER TABLE&lt;/code&gt;, &lt;code&gt;DROP TABLE&lt;/code&gt;, &lt;code&gt;TRUNCATE&lt;/code&gt;, &lt;code&gt;REINDEX&lt;/code&gt;, &lt;code&gt;VACUUM FULL&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The important rule: &lt;strong&gt;you don’t pick the lock — the statement does.&lt;/strong&gt; &lt;code&gt;SELECT&lt;/code&gt; always takes &lt;code&gt;ACCESS SHARE&lt;/code&gt;. &lt;code&gt;ALTER TABLE&lt;/code&gt; always takes &lt;code&gt;ACCESS EXCLUSIVE&lt;/code&gt;. You don’t get a vote; Postgres just does whatever the statement requires before executing it. The three ways to ask for a specific lock yourself:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;SELECT ... FOR UPDATE / FOR SHARE / FOR NO KEY UPDATE / FOR KEY SHARE&lt;/code&gt;&lt;/strong&gt; — picks a &lt;em&gt;row-level&lt;/em&gt; lock mode by name. Covered in the next subsection.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;LOCK TABLE orders IN ACCESS EXCLUSIVE MODE&lt;/code&gt;&lt;/strong&gt; — takes a table-level lock at exactly the mode you specify, no statement attached. Useful when you’re about to run several &lt;code&gt;ALTER TABLE&lt;/code&gt;s and want one acquisition at the start of the transaction instead of each statement re-acquiring it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;pg_advisory_lock(key)&lt;/code&gt; and friends&lt;/strong&gt; — application-defined locks keyed by an integer. Covered in section 8.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;compatibility-which-modes-can-share-an-object&quot;&gt;Compatibility: which modes can share an object&lt;/h3&gt;
&lt;p&gt;Once a mode is held on an object, the conflict matrix decides whether the next request is granted or made to wait. Rows are what’s already held; columns are what’s being requested. Blank means “compatible — grant immediately”; ✗ means “conflict — wait in queue.”&lt;/p&gt;








































































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Held ↓ \ Requested →&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;AS&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;RS&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;RE&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;SUE&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;S&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;SRE&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;E&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;AE&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;ACCESS SHARE&lt;/code&gt; (AS)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;ROW SHARE&lt;/code&gt; (RS)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;ROW EXCLUSIVE&lt;/code&gt; (RE)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;SHARE UPDATE EXCLUSIVE&lt;/code&gt; (SUE)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;SHARE&lt;/code&gt; (S)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;SHARE ROW EXCLUSIVE&lt;/code&gt; (SRE)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;EXCLUSIVE&lt;/code&gt; (E)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;ACCESS EXCLUSIVE&lt;/code&gt; (AE)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;How the two tables connect: the first tells you which mode your statement &lt;em&gt;asks for&lt;/em&gt;; the second tells you &lt;em&gt;whether you get it now or queue&lt;/em&gt;. A &lt;code&gt;SELECT&lt;/code&gt; (asks for AS) running on a table where someone holds AE (a slow &lt;code&gt;ALTER TABLE&lt;/code&gt;) — table 1 says ACCESS SHARE is the requested mode, table 2’s AE row says every requested mode is blocked, so your &lt;code&gt;SELECT&lt;/code&gt; waits. The &lt;code&gt;pg_locks&lt;/code&gt; view is essentially this matrix in motion: at any moment it shows you what’s held, what’s requested, and whether each request was granted (&lt;code&gt;granted = true&lt;/code&gt;) or queued.&lt;/p&gt;
&lt;p&gt;A few entries in the matrix worth committing to memory:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The bottom-right cell — &lt;strong&gt;&lt;code&gt;ACCESS EXCLUSIVE&lt;/code&gt; blocks &lt;code&gt;ACCESS SHARE&lt;/code&gt;&lt;/strong&gt; — is why a careless &lt;code&gt;ALTER TABLE&lt;/code&gt; freezes every &lt;code&gt;SELECT&lt;/code&gt; on the table.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SHARE UPDATE EXCLUSIVE&lt;/code&gt; conflicts with itself, which is why two &lt;code&gt;VACUUM&lt;/code&gt;s on the same table can’t run in parallel. &lt;code&gt;CREATE INDEX CONCURRENTLY&lt;/code&gt; exists at exactly this mode — gentle enough not to block reads or writes, but two &lt;code&gt;CONCURRENTLY&lt;/code&gt; builds on the same table still serialize.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SHARE&lt;/code&gt; and &lt;code&gt;SHARE&lt;/code&gt; &lt;em&gt;don’t&lt;/em&gt; conflict, so two non-concurrent &lt;code&gt;CREATE INDEX&lt;/code&gt; statements on different indexes of the same table can run in parallel (they both just read the heap).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;row-level-locks-a-different-mechanism&quot;&gt;Row-level locks (a different mechanism)&lt;/h3&gt;
&lt;p&gt;Postgres does &lt;strong&gt;not&lt;/strong&gt; keep per-row entries in the cluster-wide lock table. There would be far too many of them. Instead, row-level locks live in the row’s own tuple header — specifically, the &lt;code&gt;xmax&lt;/code&gt; field gets stamped with the locker’s XID, plus a flag indicating “this is a lock, not a delete.” This is brilliantly cheap (free in storage) but has a consequence: &lt;strong&gt;you can’t tell, from the lock table, who is row-locking what without joining against the tuple header&lt;/strong&gt;. The view &lt;code&gt;pg_locks&lt;/code&gt; shows row-level locks only as &lt;code&gt;tuple&lt;/code&gt; rows on rows that are currently being waited on; non-contended row locks don’t appear at all.&lt;/p&gt;
&lt;p&gt;Four row-lock modes, from weakest to strongest:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;FOR KEY SHARE&lt;/code&gt; — taken by foreign-key checks. Blocks &lt;code&gt;UPDATE&lt;/code&gt; of indexed columns.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FOR SHARE&lt;/code&gt; — explicit shared lock.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FOR NO KEY UPDATE&lt;/code&gt; — taken by &lt;code&gt;UPDATE&lt;/code&gt; that doesn’t touch the primary key.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FOR UPDATE&lt;/code&gt; — the strong one. Blocks everyone, including FK checks.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most application code reaches for &lt;code&gt;SELECT ... FOR UPDATE&lt;/code&gt; (covered in the &lt;a href=&quot;/blog/acid-properties-and-isolation-levels/&quot;&gt;ACID post&lt;/a&gt;). The weaker modes are mostly internal but visible when foreign keys cause unexpected contention — an &lt;code&gt;UPDATE&lt;/code&gt; on the parent row competes with FK checks on every child.&lt;/p&gt;
&lt;h3 id=&quot;lightweight-locks--the-internal-layer&quot;&gt;Lightweight locks — the internal layer&lt;/h3&gt;
&lt;p&gt;Heavyweight locks are &lt;em&gt;transactional&lt;/em&gt; — held until &lt;code&gt;COMMIT&lt;/code&gt;. LWLocks are &lt;em&gt;operational&lt;/em&gt; — held for microseconds while a backend reads or writes a shared-memory structure. Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pinning a buffer in &lt;code&gt;shared_buffers&lt;/code&gt; (so it isn’t evicted while you read it).&lt;/li&gt;
&lt;li&gt;Inserting a record into the WAL.&lt;/li&gt;
&lt;li&gt;Reading the cluster-wide lock table (yes, the lock table itself is LWLock-protected).&lt;/li&gt;
&lt;li&gt;Updating the visibility map.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;LWLocks have only two modes — SHARED and EXCLUSIVE — and don’t deadlock-check (they’re held for so short a time that detection would cost more than the deadlock). If a backend is spending real time blocked on an LWLock, something is wrong further up: too many backends contending on one buffer, an &lt;code&gt;XLogInsert&lt;/code&gt; bottleneck, or a hot lock-table partition.&lt;/p&gt;
&lt;p&gt;The wait events distinguish them clearly. In &lt;code&gt;pg_stat_activity.wait_event_type&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Lock&lt;/code&gt; — waiting for a heavyweight lock. Probably your application code or a long transaction.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LWLock&lt;/code&gt; — waiting on an internal lock. Probably a Postgres configuration or workload issue.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BufferPin&lt;/code&gt; — waiting to pin a buffer that something else is preventing eviction of. Rare.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IO&lt;/code&gt; — waiting on disk or the OS page cache. Not a lock at all.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Client&lt;/code&gt; — waiting on the client to send the next command (idle in transaction).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Different wait_event_types, completely different fixes.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;5-mvcc-under-the-hood&quot;&gt;5. MVCC Under the Hood&lt;/h2&gt;
&lt;p&gt;The semantics of MVCC live in the &lt;a href=&quot;/blog/acid-properties-and-isolation-levels/&quot;&gt;ACID post&lt;/a&gt;: every transaction sees a snapshot, readers don’t block writers, snapshot isolation. The mechanics are simpler than they sound.&lt;/p&gt;
&lt;h3 id=&quot;the-tuple-header&quot;&gt;The tuple header&lt;/h3&gt;
&lt;p&gt;Every row in Postgres carries hidden columns alongside its user-defined columns. You can see them:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; xmin, xmax, ctid, &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; accounts &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 42&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;xmin&lt;/code&gt; — the XID of the transaction that &lt;em&gt;inserted&lt;/em&gt; this tuple.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xmax&lt;/code&gt; — the XID of the transaction that &lt;em&gt;deleted or updated&lt;/em&gt; it (zero if neither).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ctid&lt;/code&gt; — the physical address &lt;code&gt;(page, offset)&lt;/code&gt; of the tuple on disk.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When you &lt;code&gt;UPDATE&lt;/code&gt; a row:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The current tuple’s &lt;code&gt;xmax&lt;/code&gt; is set to your XID.&lt;/li&gt;
&lt;li&gt;A new tuple is written, with &lt;code&gt;xmin = your XID&lt;/code&gt; and &lt;code&gt;xmax = 0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The new tuple’s &lt;code&gt;ctid&lt;/code&gt; points back to where the row physically lives now.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The old tuple is still on disk. It will be visible to any transaction whose snapshot was taken before your commit, and invisible to any started after. Once no snapshot can see the old tuple anymore, vacuum reclaims the space.&lt;/p&gt;
&lt;h3 id=&quot;snapshots&quot;&gt;Snapshots&lt;/h3&gt;
&lt;p&gt;A snapshot is taken at the start of a transaction (under &lt;code&gt;READ COMMITTED&lt;/code&gt;, also at the start of each statement). Conceptually:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;snapshot = {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  xmin: lowest active XID at snapshot time,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  xmax: next XID that will be assigned,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  active: list of XIDs that were in-progress at snapshot time,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The visibility rule, in one sentence: &lt;strong&gt;a tuple is visible to a snapshot if the transaction that inserted it had committed before the snapshot was taken, and the transaction that deleted it (if any) hadn’t.&lt;/strong&gt; That’s the whole of MVCC visibility. Everything else — repeatable reads, read-your-writes, why long transactions cause bloat — falls out of that single rule.&lt;/p&gt;
&lt;p&gt;In code, this means checking the tuple’s &lt;code&gt;xmin&lt;/code&gt; against the snapshot (“did the inserter finish in time?”) and its &lt;code&gt;xmax&lt;/code&gt; against the snapshot (“did the deleter, if any, finish in time?”). The Postgres source for the check lives in &lt;code&gt;HeapTupleSatisfiesMVCC&lt;/code&gt;; you almost never need to look at it.&lt;/p&gt;
&lt;h3 id=&quot;hot-updates-the-optimization-that-matters&quot;&gt;HOT updates (the optimization that matters)&lt;/h3&gt;
&lt;p&gt;If an &lt;code&gt;UPDATE&lt;/code&gt; doesn’t change any indexed column, Postgres can perform a &lt;strong&gt;HOT (Heap-Only Tuple) update&lt;/strong&gt;: the new tuple is written to the same page if there’s room, and the indexes don’t need updating because they still point to the old &lt;code&gt;ctid&lt;/code&gt;, which forwards to the new one. HOT updates massively reduce index bloat on update-heavy tables.&lt;/p&gt;
&lt;p&gt;Concrete consequence: &lt;strong&gt;adding an index on a frequently-updated column can dramatically slow down updates&lt;/strong&gt;, because every update on a row now mutates an indexed column and forces a full index entry for the new tuple. This is one of the silent reasons “we added an index and writes got worse.”&lt;/p&gt;
&lt;h3 id=&quot;vacuum-the-garbage-collector&quot;&gt;Vacuum: the garbage collector&lt;/h3&gt;
&lt;p&gt;Dead tuples (&lt;code&gt;xmax&lt;/code&gt; &amp;#x3C; oldest active snapshot’s &lt;code&gt;xmin&lt;/code&gt;) can be reclaimed. &lt;strong&gt;Autovacuum&lt;/strong&gt; is the background daemon that does this periodically per table, based on dead-row thresholds. The user-facing consequences:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Long-running transactions delay vacuum.&lt;/strong&gt; A transaction that started two hours ago has a snapshot two hours old. Vacuum can’t reclaim anything newer than that. Dead tuples pile up. Tables bloat.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;VACUUM&lt;/code&gt; (non-FULL) is online.&lt;/strong&gt; It acquires &lt;code&gt;SHARE UPDATE EXCLUSIVE&lt;/code&gt;, which conflicts only with schema changes and other vacuums. Reads and writes continue.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;VACUUM FULL&lt;/code&gt; is offline.&lt;/strong&gt; It rewrites the entire table, taking &lt;code&gt;ACCESS EXCLUSIVE&lt;/code&gt;. Don’t run it on a live production table without a maintenance window. Use &lt;code&gt;pg_repack&lt;/code&gt; (or its bundled extensions) instead — it does the same job online, locking only for the final swap.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;xid-wraparound&quot;&gt;XID wraparound&lt;/h3&gt;
&lt;p&gt;XIDs are 32 bits — 4.3 billion of them. Postgres uses a circular comparison: at any moment, half the space is “past” and half is “future.” If a tuple’s &lt;code&gt;xmin&lt;/code&gt; would be older than the past half (&gt;2 billion XIDs old), it becomes invisible to everyone — a silent data-loss condition.&lt;/p&gt;
&lt;p&gt;Autovacuum prevents this by &lt;strong&gt;freezing&lt;/strong&gt; old tuples: rewriting their &lt;code&gt;xmin&lt;/code&gt; as a special “frozen” sentinel that’s visible to every future snapshot. The &lt;code&gt;vacuum_freeze_max_age&lt;/code&gt; setting controls how aggressive freezing is. If autovacuum can’t keep up, you eventually see warnings like &lt;code&gt;database &quot;x&quot; must be vacuumed within N transactions&lt;/code&gt;. At 1 million transactions remaining, Postgres refuses new writes and enters &lt;strong&gt;single-user mode&lt;/strong&gt; until you run a manual emergency vacuum.&lt;/p&gt;
&lt;p&gt;This used to be the most embarrassing Postgres outage class — entire shops taken offline by XID exhaustion. Postgres 14+ defaults plus monitoring of &lt;code&gt;pg_database.datfrozenxid&lt;/code&gt; have mostly retired it, but it’s still the reason “autovacuum is healthy” is not a question you skip on a production cluster.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;6-deadlocks-and-how-theyre-resolved&quot;&gt;6. Deadlocks and How They’re Resolved&lt;/h2&gt;
&lt;p&gt;A deadlock is the most boring kind of concurrency bug: two transactions, each waiting on a lock the other one is holding, neither willing to give up. They’d wait forever if nothing intervened.&lt;/p&gt;
&lt;p&gt;Postgres notices. Whenever a backend has been waiting on a lock for longer than &lt;code&gt;deadlock_timeout&lt;/code&gt; (default 1 second), Postgres walks the “who’s waiting on whom” graph looking for cycles. If it finds one, it picks a victim and kills it:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ERROR:  deadlock detected&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;DETAIL:  Process 1234 waits for ShareLock on transaction 5678; blocked by process 4321.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         Process 4321 waits for ShareLock on transaction 5679; blocked by process 1234.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;HINT:  See server log for query details.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;SQLSTATE: 40P01&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The other transaction proceeds. The aborted transaction’s client should retry.&lt;/p&gt;
&lt;h3 id=&quot;the-classic-cause-inconsistent-lock-ordering&quot;&gt;The classic cause: inconsistent lock ordering&lt;/h3&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 1015 1446&quot;&gt;&lt;svg class=&quot;d2-3314018228 d2-svg&quot; width=&quot;1015&quot; height=&quot;1446&quot; viewBox=&quot;-13 27 1015 1446&quot;&gt;&lt;rect x=&quot;-13.000000&quot; y=&quot;27.000000&quot; width=&quot;1015.000000&quot; height=&quot;1446.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-3314018228 .text {
	font-family: &quot;d2-3314018228-font-regular&quot;;
}
@font-face {
	font-family: d2-3314018228-font-regular;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-3314018228 .text-italic {
	font-family: &quot;d2-3314018228-font-italic&quot;;
}
@font-face {
	font-family: d2-3314018228-font-italic;
	src: url(&quot;data:application/font-woff;base64,d09GRgABAAAAABMMAAoAAAAAHRgAARhRAAAAAAAAAAAAAAAAAAAAAAAAAABPUy8yAAAA9AAAAGAAAABgW1SVeGNtYXAAAAFUAAAAxQAAARApNyVcZ2x5ZgAAAhwAAAvoAAAQ1MogHX9oZWFkAAAOBAAAADYAAAA2G7Ur2mhoZWEAAA48AAAAJAAAACQLeAjdaG10eAAADmAAAADPAAAA5GolB31sb2NhAAAPMAAAAHQAAAB0fV6BxG1heHAAAA+kAAAAIAAAACAAUQD2bmFtZQAAD8QAAAMmAAAIMgntVzNwb3N0AAAS7AAAACAAAAAg/8YAMgADAeEBkAAFAAACigJY//EASwKKAlgARAFeADIBIwAAAgsFAwMEAwkCBCAAAHcAAAADAAAAAAAAAABBREJPAAEAIP//Au7/BgAAA9gBESAAAZMAAAAAAeYClAAAACAAA3ichM+7LkMBHMfxz2mPe93rrpzWtRxU1WgwSgwikc5GsYvn8AreACviRYSnkDD8JScx+82f5JsfEmUJKtIkRUMmVZLZ0JRr6zhy4syFris3brNq/S6CwmzKtQpz7NS5rkvXfyY+DRhUjp/4jq94i9d4ied4isd4+Ki93xfl/5ZoaTuwZ1tux66OkrJUj159+ovGkIphI0aNGTdhUtWUaTNmzZm3YFHNkmWZuoYVq9asFw+atuw75BcAAP//AQAA//8ZCynAAAAAeJx8V2twG9d1vvfuEssH+AAWWAgQCRBYYJcEFw9igV2AJECQIAESDz5FipZIkHpafESBJdOPSEpsccaV3bEKe9R47HGjtHY7afyjHjn9kT6cOkpnWLvKtB2ndZtOOh47cio1E4vDepxMuejcBUiCmjZ/FjuDvefc853v+869oAY4AUDn0Q1AgDrQDPTACIBI2wlClGXWRIg8z1KUzNM05bwKN6++RiaO/bzj278WbGTq2T/N/NfSW+jGzhp8ZuEb31COXztz5uj9+4ob/vN9AABApQ8AgD9BRVAHdADQlMhzHM9qNBCKNMuz1Cc9t+vJepK0iMrfw9PHspP6XyzDpwuF4Eo48qgyiYo7hTt3ACAACwBqR0WgAxb8LtJigDEaNBqKYtRflhADUijIsfsv7MafLa51JZxQTKYuj/Xk88eG08dXL+TP50YfR8V0ShgSakntQHh0QYBPpGRPYOfecDYQxfuGIFLaRh70OrABUOPguFAwhsQAY6I4jnU0IaOBYcSAJJs0GujInJP8x65kw5OHJFriehYHnY50b0einXUuaBNPjeVuPJmS3Z3tfPT0U329C6H2wwGbB2Oj1iSp2NBVFbG8GJB2K/ja8y/O3Pzq7OzM5cSjpyRU/J2nn/zemfiRb55YWC7vE8doQUXQoPaMslMixVJ2it2AK43KJ+4HTb8SIdeEigM/GfxisOr7uqrvicrXngeNn/eh4sCng8q/7GLQi14HDhWD/wcCmZVFQqOBwhNX/MefneydNMu03BE7Oexks/3OCO261vjjiDOvfempsRtPJveA6MlLh1r+PK58anXt1bG8W4dI2GmRYGk7wW6MhWFHOLcx1q98FENF5T407hRgWNksrwHbqAiI8hp2Y2wDE2Y3HnwZFUFNJR7Fbow9AQ2NqLhzaxeHv0JFYFb/p02irGaUJJmlCJbAHKUIdmMhwpDJ2wsbmWydRUuOvydEGVLTVJtGReVb167BkzsFeEFY6XpZeRPOvywsC8r1SuyzqFjpKm0SJUmNvhd17JtuUtNUP5zZyN3oIjXN9UlUVOaf7/6KCOd3CvCNF8WVgHJT5UhfaRvl0eugBbRXd4ExGpoQH4ghzJNyN6Dt/Lp3dj2ZPhP0zj6eCB2NOdJj+DmqfeVyprg+PHRpOvPS+nCi7+R65MR678n1nqUn9njoUbE3VPOQJeh9KX1//kL62SPLwYHFMyvZkTOomJ6deLRb+RKmJsYjItiLw6MiaATMfhyKZokDkb43/9j56YvTaxfkoVP505mRJVRMTh8/r1M+gYxyD85MJSVfmdva0jZU0OvADYDJwfGySrhQkON5LEhJ2mOjRmM0MCZT2Qk+SxQ6Im0zct+kx5V194bme3uXbKI56XWF2rqdWV+w96y2p6erKzAUdgYYr2VUDkwFgh1ea6fNf5jzMZ7WlNxzPAggWAAAhVARULgaVrZTLPEn6+82wg8af7COconEzjvlfY6XttV+M5UOqd3GW8L6oFV1WE+vasj0WKYuPhw+ZpzMTrVe1S6fNfrMsKA873Ekc/Or8GVl9frTON4iAISAisBe5q5GQ5UZRDMGY/kNskRQklU2LdZN1BMESZr8zJupOkgaugzXc8rWKQpBssmuewcVlVeCa6HQWhAuK68EVyVpNQiXdwrwJec4z2d55atq7/jSNvwSbgED7qJpX+2iLBIszsRjre9J/514VkjnRT6qI+nYif5akp3Tc+NOwRhodSZCtm7t8Znk0/Nihz2qWEZcvrjX96+cwz26EOiPlrliK23Dz9EmMOLpg7vLUiwtUrhSlTdV7FY9/h4f1RGG/us5nkHOIx41fciZCFn9nY5J1msQtR32KNp8d6mt69gsTh13jy6Isajb9RnnABC4StvwFtwCrQeq22dPxc0/Gj8t5E6EhD7GQ3Nt/lkp0tMuMQ5LTnt2YejijM9h9puMQ4XEYNKiCxhcYBc7xFfVso/dbwevR0+0cLliBb0x18Po8e2L7+6EH4YPqbX8AG4BC3BV51PVZtfsTSZCVMcIrvDT2WVPZt4vD1i1NcqP6toT7raIydo2+WoJEfpONpTXrpwYLkwJ3olAq9jUP+Ey60SjDboaDjW2dttmAARdAMAX0YfApGqhH1Wrj1KHSNdMf8NAS/NY1OLWH64/rLN31upOak/NwO9EaibT040NMlUf6JqOKXMYM1hywi24BWzAW61uWdZo2IPs02iIA+i91T3LOluHO2LpJjN3xBed6Bqd7+ZiOoLuP0tfjLCTji6mu5UdEK2+f+faQiZHNn6OE2ZnEo8/EsB8JBbPQnuX+x84R2dyzt/bW9awDQD4EdqszIN9HlLqUAgFcZmE7XrO30J2TgmxUG0s20eSI60j3mG0eT/K+gbCNqfyPhQMhxozbq/ynVIJxwS/QbcQByQAgAbII/u5fok2gbasb5yPZnmKsl3PLaFfz/1wfWyhYEGbShuEHyg//+WFSwACobQNfoM2gR6jFQqWbcVoqLT6KwOaS7krEOoIDQXrGW2/zoxWd16i6gg9RL0kuZcX3YNb2E9xznKJpkqhmgOVVhd9op8iuWmup7vGN+eKSiQZy0VJMmUcEYYxBklmpGsY3h11dssdgjgQ1lkN1Tjsv+3jDLfAoeo9PAwzztg55T2AsprhYZD39Ad/CrdAM2ir1kPZRMpHqbLIPxzPC+l8YHxRyOTdnklRCuCH9tzx4Ysz3vIzPlgYGkwlCkODSfX8+kVJhJ/DrbK2qaodNyFWdS2KPuBT9S/0awjXjFeVeIDro5He9sfVPnUHvRO3eSoCt527CWHFqLhfuOy79YiqF6s5a2RsIA9p4qAioN1uRa45b7Unv3Cz2lDu3HyS8+1Z8k4OwoOGXO7LZbgFWqr6YqK43X40kG1Zj9l4uMXizNqi8O6CEK0bqu3vVe4AWPqf0ja8ArcA//CcfnhM4yldHtJvdC+Y/aY45452hr0RYVTwplu9tGjnuqX2WNA/pQ12cLYOL2vhbZZYZ9eAy2ntMFg8Niund/QJniEX3nNfaRvOobU9T5dk7Eyi6kZVnv79eJCEkVRD1jlw+JL2SoRodTRZGnQtPm2/p9nSCPWRmueeiyn39Hqrtb5Gpppx7HBpG/4K3sV+YNqf6RXF0RVbf2tPDSNtKWE4iwdhxxHtoKyz0VBSPqTNmKZwTrGkWbGswV4A4MfwLmgEACufYSqnQ3g1lXWSGpLUOenfyyk78K7yGZthnaNOaFYs6trShwDAfyrviaV50VRZLIuUia3cqyhK+LfjY+7aJopsbm+emd48NS7U6urJFgedh+jTNYY3GjqNa//94ALjZRjBdBHzzV3ahj9GLwAdPnGY9m87/8chczOQcrlHl0KBpLNzdLGbTwTbBK/61IZPxR75w8upnlOxY9++lIwOPXZtKHF0+LFrQ4NHAQQWAOAz6Ovq+V7GpylJFgmRsjT+7tJj9TNy7+NXtXH4s4DWsfPDOK71CwDgj9ALeB0rx4iKwPg98VF2qr526XreJ4baBxy8cNQ/NeeeujwNDVrv5KWTj3iFPrvNz3U+MhTKLxVGBnGduLF30NdBPT7n2lnZLkO8B9YlylL5NAUzI6zyn3Uwf2RiWjutlP6W0+gp0tBheDsIX1MKsdhftw3YW4OHyv34uDQPimANawbvTFZFWnFTQ4MvQiHGyrZZWo+96dX3OS2MmXdaRwtlHjwDvwseoJv4fkLjDlLPmJoztBt+99X5+VfVO8TH6GfQhO82Mj55NqC3Gz6WJHXtQGkCHkU/xfWYyhKTTRr1Qmb62iG7fC7tWVmrMzS9HX9jav3v/nLB/JzyH9/ynl3iVA6VJsC9ylpe0uPzARYs1iT0rKzW6ZsDOMTblueg/Q98Zxc5Ov5HU+vv/wUolYAf3Ibvw39EHAiDFaABYfD76n4Mpc9RDNXgO2UNL9tDdl6GRhjmbytx+De3eahpcb/X/55b+bJmbw6BO/Du7r3NdiJ3Et5VSQ5BCmXALXQL84SugvMp2sqaDG0sypgYs/0QY24HEPihF74PH8Vx6JDd6IevQW8kAgD4XwAAAP//AQAA//9PrYwAAAEAAAABGFHW1huvXw889QABA+gAAAAA2F2gzAAAAADdZi83/r3+3QgdA8kAAgADAAIAAAAAAAAAAQAAA9j+7wAACED+vf28CB0D6ADC/9EAAAAAAAAAAAAAADl4nByNoUpDYRxHz+93o4qCwnTlC3/vLjiD0eGKQVYEtdjEKggmi81n8D1MvoA2QTBZBMO3B7AMmSJjn1zjgXM4vmaTZ9C8vHhEuMfAx4S+Cb0TPmTgK4IZoVfCT4QvCd8wdI9wn9Avi5pz5guO/MW5N2i8TtIDtTs0GlOrS9+ryAskPkn6IPHDdpVIXiK5onGnTNtWpyTdlZkOGHqFXT2yp/vypsyWMl3lMlVmmUkZM+G2EqFgX/W/s+MT1toHMGr5DwAA//8BAAD///2BMuIAAAAALgAuAFIAigC8AN4A9gEMAUIBXAFqAXoBqAHOAgACJAJMAowCoALIAwIDOgNyA6AD2AQSBDoEggSsBLgE0gT0BTYFYAWOBcgGAgYgBlwGiga2BtQHAAcyB0oHdAecB7oHygfYB/YIFAggCDgIRghcCGoAAQAAADkAjAAMAGYABwABAAAAAAAAAAAAAAAAAAQAA3icnJTbThtXFIY/B9tterqoUERu0L5MpWRMoxAl4cqUoIyKcOpxepCqSoM9PojxzMgzmJIn6HXfom+Rqz5Gn6LqdbV/L4MdRUEgBPx79jr8a61/bWCT/9igVr8L/N2cG66x3fzZ8B2+aB4Z3mC/+ZnhOg8b/xhuMGi8NdzkQaNr+BPe1f80/ClP6r8ZvstW/dDw5zyubxr+csPxr+GveMK7Ba7BM/4wXGOLwvAdNvnV8Ab3sJi1OvfYMdzga7YNN9kGekyoSJmQMcIxZMKIM2YklEQkzJgwJGGAI6RNSqWvGbGQY/TBrzERFTNiRRxT4UiJSIkpGVvEt/LKea2MQ51mdtemYkzMiTxOiclw5IzIyUg4VZyKioIXtGhR0hffgoqSgJIJKQE5M0a06HDIET3GTChxHCqSZxaRM6TinFj5nVn4zvRJyCiN1RkZA/F04pfIO+QIR4dCtquRj9YiPMTxo7w9t1y23xLo160wW8+7ZBMzVz9TdSXVzbkmONatz9vmB+GKF7hb9WedyfU9Guh/pcgnnGn+A00qE5MM57ZoE0lBkbuPY1/nkEgd+YmQHq/o8Iaezm26dGlzTI+Ql/Lt0MXxHR2OOZBHKLy4O5RijvkFx/eEsvGxE+vPYmIJv1OYuktxnKmOKYV67pkHqjVRhTefsN+hfE0dpXz62iNv6TS/THsWMzJVFGI4VS+X2iitfwNTxFS1+Nle3fttmNvuLbf4glw77NW64OQnt2B03VSD9zRzrp+AmAE5J7LokzOlRcWFeL8m5owUx4G690pbUtG+9PF5LqSShKkYhGSKM6PQ39h0Exn3/prunb0lA/l7pqeXVd0mi1Ovrmb0Rt1b3kXW5WRlAi2bar6ipr64Zqb9RDu1yj+Sb6nXLecRoeIudvtDr8AOz9llj7Gy9HUzv7zzr4S32FMHTklkNZSmfQ2PCdgl4Cm77PKcp+/1csnGGR+3xmc1f5sD9umwd201C9sO+7xci/bxzH+J7Y7qcTy6PD279TQf3EC132jfrt7NribnpzG3aFfbcUzM1HNxW6s1ufsE/wMAAP//AQAA//9yoVFAAAAAAwAA//UAAP/OADIAAAAAAAAAAAAAAAAAAAAAAAAAAA==&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-3314018228 .fill-N1{fill:#0A0F25;}
		.d2-3314018228 .fill-N2{fill:#676C7E;}
		.d2-3314018228 .fill-N3{fill:#9499AB;}
		.d2-3314018228 .fill-N4{fill:#CFD2DD;}
		.d2-3314018228 .fill-N5{fill:#DEE1EB;}
		.d2-3314018228 .fill-N6{fill:#EEF1F8;}
		.d2-3314018228 .fill-N7{fill:#FFFFFF;}
		.d2-3314018228 .fill-B1{fill:#0D32B2;}
		.d2-3314018228 .fill-B2{fill:#0D32B2;}
		.d2-3314018228 .fill-B3{fill:#E3E9FD;}
		.d2-3314018228 .fill-B4{fill:#E3E9FD;}
		.d2-3314018228 .fill-B5{fill:#EDF0FD;}
		.d2-3314018228 .fill-B6{fill:#F7F8FE;}
		.d2-3314018228 .fill-AA2{fill:#4A6FF3;}
		.d2-3314018228 .fill-AA4{fill:#EDF0FD;}
		.d2-3314018228 .fill-AA5{fill:#F7F8FE;}
		.d2-3314018228 .fill-AB4{fill:#EDF0FD;}
		.d2-3314018228 .fill-AB5{fill:#F7F8FE;}
		.d2-3314018228 .stroke-N1{stroke:#0A0F25;}
		.d2-3314018228 .stroke-N2{stroke:#676C7E;}
		.d2-3314018228 .stroke-N3{stroke:#9499AB;}
		.d2-3314018228 .stroke-N4{stroke:#CFD2DD;}
		.d2-3314018228 .stroke-N5{stroke:#DEE1EB;}
		.d2-3314018228 .stroke-N6{stroke:#EEF1F8;}
		.d2-3314018228 .stroke-N7{stroke:#FFFFFF;}
		.d2-3314018228 .stroke-B1{stroke:#0D32B2;}
		.d2-3314018228 .stroke-B2{stroke:#0D32B2;}
		.d2-3314018228 .stroke-B3{stroke:#E3E9FD;}
		.d2-3314018228 .stroke-B4{stroke:#E3E9FD;}
		.d2-3314018228 .stroke-B5{stroke:#EDF0FD;}
		.d2-3314018228 .stroke-B6{stroke:#F7F8FE;}
		.d2-3314018228 .stroke-AA2{stroke:#4A6FF3;}
		.d2-3314018228 .stroke-AA4{stroke:#EDF0FD;}
		.d2-3314018228 .stroke-AA5{stroke:#F7F8FE;}
		.d2-3314018228 .stroke-AB4{stroke:#EDF0FD;}
		.d2-3314018228 .stroke-AB5{stroke:#F7F8FE;}
		.d2-3314018228 .background-color-N1{background-color:#0A0F25;}
		.d2-3314018228 .background-color-N2{background-color:#676C7E;}
		.d2-3314018228 .background-color-N3{background-color:#9499AB;}
		.d2-3314018228 .background-color-N4{background-color:#CFD2DD;}
		.d2-3314018228 .background-color-N5{background-color:#DEE1EB;}
		.d2-3314018228 .background-color-N6{background-color:#EEF1F8;}
		.d2-3314018228 .background-color-N7{background-color:#FFFFFF;}
		.d2-3314018228 .background-color-B1{background-color:#0D32B2;}
		.d2-3314018228 .background-color-B2{background-color:#0D32B2;}
		.d2-3314018228 .background-color-B3{background-color:#E3E9FD;}
		.d2-3314018228 .background-color-B4{background-color:#E3E9FD;}
		.d2-3314018228 .background-color-B5{background-color:#EDF0FD;}
		.d2-3314018228 .background-color-B6{background-color:#F7F8FE;}
		.d2-3314018228 .background-color-AA2{background-color:#4A6FF3;}
		.d2-3314018228 .background-color-AA4{background-color:#EDF0FD;}
		.d2-3314018228 .background-color-AA5{background-color:#F7F8FE;}
		.d2-3314018228 .background-color-AB4{background-color:#EDF0FD;}
		.d2-3314018228 .background-color-AB5{background-color:#F7F8FE;}
		.d2-3314018228 .color-N1{color:#0A0F25;}
		.d2-3314018228 .color-N2{color:#676C7E;}
		.d2-3314018228 .color-N3{color:#9499AB;}
		.d2-3314018228 .color-N4{color:#CFD2DD;}
		.d2-3314018228 .color-N5{color:#DEE1EB;}
		.d2-3314018228 .color-N6{color:#EEF1F8;}
		.d2-3314018228 .color-N7{color:#FFFFFF;}
		.d2-3314018228 .color-B1{color:#0D32B2;}
		.d2-3314018228 .color-B2{color:#0D32B2;}
		.d2-3314018228 .color-B3{color:#E3E9FD;}
		.d2-3314018228 .color-B4{color:#E3E9FD;}
		.d2-3314018228 .color-B5{color:#EDF0FD;}
		.d2-3314018228 .color-B6{color:#F7F8FE;}
		.d2-3314018228 .color-AA2{color:#4A6FF3;}
		.d2-3314018228 .color-AA4{color:#EDF0FD;}
		.d2-3314018228 .color-AA5{color:#F7F8FE;}
		.d2-3314018228 .color-AB4{color:#EDF0FD;}
		.d2-3314018228 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-3314018228);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-3314018228);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-3314018228);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-3314018228);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-3314018228);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-3314018228);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-3314018228);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-3314018228);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-3314018228);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-3314018228);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-3314018228);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-3314018228);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-3314018228);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-3314018228);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-3314018228);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-3314018228);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-3314018228);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-3314018228);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;QQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;12.000000&quot; y=&quot;52.000000&quot; width=&quot;194.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;109.000000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Txn A (transfer A1→A2)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Qg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;246.000000&quot; y=&quot;52.000000&quot; width=&quot;194.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;343.000000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Txn B (transfer A2→A1)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;REI=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;686.000000&quot; y=&quot;52.000000&quot; width=&quot;107.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;739.500000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Database&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLS0gKVswXQ==&quot;&gt;&lt;path d=&quot;M 109.000000 120.000000 L 109.000000 1447.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-3314018228)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLS0gKVswXQ==&quot;&gt;&lt;path d=&quot;M 343.000000 120.000000 L 343.000000 1447.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-3314018228)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KERCIC0tIClbMF0=&quot;&gt;&lt;path d=&quot;M 739.500000 120.000000 L 739.500000 1447.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-3314018228)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgREIpWzBd&quot;&gt;&lt;marker id=&quot;mk-d2-3314018228-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 111.000000 198.000000 L 735.500000 198.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3314018228-3488378134)&quot; mask=&quot;url(#d2-3314018228)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;424.500000&quot; y=&quot;204.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;BEGIN&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgREIpWzFd&quot;&gt;&lt;path d=&quot;M 111.000000 288.000000 L 735.500000 288.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3314018228-3488378134)&quot; mask=&quot;url(#d2-3314018228)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;424.000000&quot; y=&quot;294.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;SELECT FROM accounts WHERE id=&apos;A1&apos; FOR UPDATE&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KERCIC0mZ3Q7IEEpWzBd&quot;&gt;&lt;path d=&quot;M 737.500000 378.000000 L 113.000000 378.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3314018228-3488378134)&quot; mask=&quot;url(#d2-3314018228)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;424.500000&quot; y=&quot;384.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;lock acquired&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgREIpWzBd&quot;&gt;&lt;path d=&quot;M 345.000000 468.000000 L 735.500000 468.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3314018228-3488378134)&quot; mask=&quot;url(#d2-3314018228)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;541.500000&quot; y=&quot;474.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;BEGIN&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgREIpWzFd&quot;&gt;&lt;path d=&quot;M 345.000000 558.000000 L 735.500000 558.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3314018228-3488378134)&quot; mask=&quot;url(#d2-3314018228)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;541.000000&quot; y=&quot;564.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;SELECT FROM accounts WHERE id=&apos;A2&apos; FOR UPDATE&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KERCIC0mZ3Q7IEIpWzBd&quot;&gt;&lt;path d=&quot;M 737.500000 648.000000 L 347.000000 648.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3314018228-3488378134)&quot; mask=&quot;url(#d2-3314018228)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;541.500000&quot; y=&quot;654.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;lock acquired&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgREIpWzJd&quot;&gt;&lt;path d=&quot;M 111.000000 738.000000 L 735.500000 738.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3314018228-3488378134)&quot; mask=&quot;url(#d2-3314018228)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;424.000000&quot; y=&quot;744.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;SELECT FROM accounts WHERE id=&apos;A2&apos; FOR UPDATE&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgQSlbMF0=&quot;&gt;&lt;path d=&quot;M 111.000000 818.000000 L 179.000000 818.000000 S 189.000000 818.000000 189.000000 828.000000 L 189.000000 853.000000 S 189.000000 863.000000 179.000000 863.000000 L 113.000000 863.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3314018228-3488378134)&quot; mask=&quot;url(#d2-3314018228)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;189.000000&quot; y=&quot;846.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;blocks — B holds A2&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgREIpWzJd&quot;&gt;&lt;path d=&quot;M 345.000000 943.000000 L 735.500000 943.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3314018228-3488378134)&quot; mask=&quot;url(#d2-3314018228)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;541.000000&quot; y=&quot;949.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;SELECT FROM accounts WHERE id=&apos;A1&apos; FOR UPDATE&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgQilbMF0=&quot;&gt;&lt;path d=&quot;M 345.000000 1023.000000 L 413.000000 1023.000000 S 423.000000 1023.000000 423.000000 1033.000000 L 423.000000 1058.000000 S 423.000000 1068.000000 413.000000 1068.000000 L 347.000000 1068.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3314018228-3488378134)&quot; mask=&quot;url(#d2-3314018228)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;423.000000&quot; y=&quot;1051.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;blocks — A holds A1&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KERCIC0mZ3Q7IERCKVswXQ==&quot;&gt;&lt;path d=&quot;M 741.500000 1138.000000 L 853.500000 1138.000000 S 863.500000 1138.000000 863.500000 1148.000000 L 863.500000 1173.000000 S 863.500000 1183.000000 853.500000 1183.000000 L 743.500000 1183.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3314018228-3488378134)&quot; mask=&quot;url(#d2-3314018228)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;864.000000&quot; y=&quot;1166.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;deadlock detector picks B as victim&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgQilbMV0=&quot;&gt;&lt;path d=&quot;M 345.000000 1253.000000 L 413.000000 1253.000000 S 423.000000 1253.000000 423.000000 1263.000000 L 423.000000 1288.000000 S 423.000000 1298.000000 413.000000 1298.000000 L 347.000000 1298.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3314018228-3488378134)&quot; mask=&quot;url(#d2-3314018228)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;423.500000&quot; y=&quot;1281.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;ERROR 40P01&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgREIpWzNd&quot;&gt;&lt;path d=&quot;M 111.000000 1378.000000 L 735.500000 1378.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3314018228-3488378134)&quot; mask=&quot;url(#d2-3314018228)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;424.500000&quot; y=&quot;1384.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;lock A2 granted, proceeds&lt;/text&gt;&lt;/g&gt;&lt;mask id=&quot;d2-3314018228&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-13&quot; y=&quot;27&quot; width=&quot;1015&quot; height=&quot;1446&quot;&gt;
&lt;rect x=&quot;-13&quot; y=&quot;27&quot; width=&quot;1015&quot; height=&quot;1446&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;402.000000&quot; y=&quot;188.000000&quot; width=&quot;45&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;254.000000&quot; y=&quot;278.000000&quot; width=&quot;340&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;378.000000&quot; y=&quot;368.000000&quot; width=&quot;93&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;519.000000&quot; y=&quot;458.000000&quot; width=&quot;45&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;371.000000&quot; y=&quot;548.000000&quot; width=&quot;340&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;495.000000&quot; y=&quot;638.000000&quot; width=&quot;93&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;254.000000&quot; y=&quot;728.000000&quot; width=&quot;340&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;124.000000&quot; y=&quot;830.000000&quot; width=&quot;130&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;371.000000&quot; y=&quot;933.000000&quot; width=&quot;340&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;359.000000&quot; y=&quot;1035.000000&quot; width=&quot;128&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;748.000000&quot; y=&quot;1150.000000&quot; width=&quot;232&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;378.000000&quot; y=&quot;1265.000000&quot; width=&quot;91&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;338.000000&quot; y=&quot;1368.000000&quot; width=&quot;173&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;Both transactions tried to do the same thing — lock two accounts in a money transfer — but each locked them in a different order. &lt;strong&gt;The fix is canonical lock ordering&lt;/strong&gt;: always lock the row with the lower ID first.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- safe pattern&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;BEGIN&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; accounts &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;IN&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;A1&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;A2&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;   ORDER BY&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; id  &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- guarantees consistent lock order&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;   FOR&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; UPDATE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;  -- transfer logic&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;COMMIT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works because Postgres acquires row locks in row-fetch order. Two transactions hitting the same pair always lock in the same order, so no cycle is possible.&lt;/p&gt;
&lt;h3 id=&quot;when-deadlocks-are-inevitable&quot;&gt;When deadlocks are inevitable&lt;/h3&gt;
&lt;p&gt;Some workloads will deadlock no matter how you order locks — for example, &lt;code&gt;UPDATE&lt;/code&gt; on rows whose order can’t be predicted by the application. The right pattern is: &lt;strong&gt;catch the &lt;code&gt;40P01&lt;/code&gt; error, sleep with jitter, retry the transaction&lt;/strong&gt;. Most ORMs (and Postgres clients) make this trivial. Treating deadlocks as “fatal application bugs” instead of “expected concurrency outcomes” is a common over-correction.&lt;/p&gt;
&lt;h3 id=&quot;deadlock_timeout-tuning&quot;&gt;&lt;code&gt;deadlock_timeout&lt;/code&gt; tuning&lt;/h3&gt;
&lt;p&gt;Lowering &lt;code&gt;deadlock_timeout&lt;/code&gt; makes the detector run more often — fewer false-wait stalls before resolution, but more CPU spent checking. The default of 1 second is right for almost all workloads; raise it only if your monitoring shows the detector running frequently on contended tables. Lowering below 100 ms is rarely productive.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;7-observing-it-live&quot;&gt;7. Observing It Live&lt;/h2&gt;
&lt;p&gt;When the database “feels slow,” the answer almost always lives in three views.&lt;/p&gt;
&lt;h3 id=&quot;pg_stat_activity--what-every-backend-is-doing&quot;&gt;&lt;code&gt;pg_stat_activity&lt;/code&gt; — what every backend is doing&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pid, &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, wait_event_type, wait_event,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;       now&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; xact_start &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;AS&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; xact_age,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;       now&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; query_start &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;AS&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; query_age,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;       LEFT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(query, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;60&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;AS&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; query&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pg_stat_activity&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; state&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;idle&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ORDER BY&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; xact_age &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;DESC&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; NULLS&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; LAST&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;state&lt;/code&gt; — &lt;code&gt;active&lt;/code&gt; (running a query), &lt;code&gt;idle in transaction&lt;/code&gt; (the danger zone), &lt;code&gt;idle&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wait_event_type&lt;/code&gt;, &lt;code&gt;wait_event&lt;/code&gt; — what’s blocking, if anything.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xact_age&lt;/code&gt; — how long the transaction has been open. Anything over a few seconds on an OLTP system is suspicious; anything over minutes is almost certainly a bug.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;idle in transaction&lt;/code&gt; is the single most common cause of mystery contention. The application opened a transaction, took some row locks, then went off to do something slow (an external HTTP call, a &lt;code&gt;Thread.sleep&lt;/code&gt;) without committing. Every other transaction touching those rows piles up behind it.&lt;/p&gt;
&lt;h3 id=&quot;pg_locks--every-lock-in-the-cluster&quot;&gt;&lt;code&gt;pg_locks&lt;/code&gt; — every lock in the cluster&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; locktype, relation::regclass, mode, granted, pid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pg_locks&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; NOT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; granted;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ungranted locks (&lt;code&gt;granted = false&lt;/code&gt;) are the things waiting. Join &lt;code&gt;pg_locks&lt;/code&gt; to &lt;code&gt;pg_stat_activity&lt;/code&gt; by &lt;code&gt;pid&lt;/code&gt; to see which queries are stuck and on what.&lt;/p&gt;
&lt;h3 id=&quot;pg_blocking_pids--the-one-shot-diagnostic&quot;&gt;&lt;code&gt;pg_blocking_pids()&lt;/code&gt; — the one-shot diagnostic&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pid,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;       pg_blocking_pids(pid) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;AS&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; blocked_by,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;       wait_event_type, wait_event,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;       query&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pg_stat_activity&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; state&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;active&apos;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pg_blocking_pids(pid) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x3C;&gt;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;{}&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This returns, for every backend currently waiting, the list of PIDs blocking it. The output reads like a directed graph: “PID 1234 is blocked by 5678 and 5679.” Trace upwards to find the root culprit — usually one &lt;code&gt;idle in transaction&lt;/code&gt; session holding everything else hostage.&lt;/p&gt;
&lt;p&gt;If you don’t memorize any other query in this post, memorize this one. It is the single highest-leverage observation in Postgres operations.&lt;/p&gt;
&lt;h3 id=&quot;pg_stat_statements--workload-accounting-different-but-related&quot;&gt;&lt;code&gt;pg_stat_statements&lt;/code&gt; — workload accounting (different but related)&lt;/h3&gt;
&lt;p&gt;Not concurrency-specific, but the natural neighbour: query-level totals over time (calls, total time, mean time, rows). Extension, needs &lt;code&gt;CREATE EXTENSION pg_stat_statements;&lt;/code&gt; and &lt;code&gt;shared_preload_libraries&lt;/code&gt;. When &lt;code&gt;pg_blocking_pids&lt;/code&gt; shows a query holding everyone else up, &lt;code&gt;pg_stat_statements&lt;/code&gt; shows how often that query runs and how slow it is on average.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;8-advisory-locks&quot;&gt;8. Advisory Locks&lt;/h2&gt;
&lt;p&gt;Postgres exposes its lock manager directly to application code via &lt;strong&gt;advisory locks&lt;/strong&gt;. They have no semantic meaning to Postgres — they’re keyed by a 64-bit integer (or a pair of 32-bit integers) that you assign and interpret. Two clients that agree on what key &lt;code&gt;42&lt;/code&gt; means can use it to serialize work.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- session-scoped: released when the session ends or you release explicitly&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pg_advisory_lock(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;42&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- ... critical section ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pg_advisory_unlock(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;42&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- transaction-scoped: released automatically at COMMIT/ROLLBACK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pg_advisory_xact_lock(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;42&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- ... critical section ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;COMMIT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are blocking and non-blocking variants:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pg_advisory_lock(key)&lt;/code&gt; — blocks until acquired.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pg_try_advisory_lock(key)&lt;/code&gt; — returns &lt;code&gt;true&lt;/code&gt; if acquired, &lt;code&gt;false&lt;/code&gt; if held by someone else. The “I’ll try, but skip if busy” pattern.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;when-to-reach-for-them&quot;&gt;When to reach for them&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Idempotent batch jobs.&lt;/strong&gt; A nightly cron is invoked by two replicas of your scheduler at the same time. Wrap the job in &lt;code&gt;pg_try_advisory_xact_lock(job_id)&lt;/code&gt;; the second invocation no-ops.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Leader election when you already have a Postgres.&lt;/strong&gt; One worker holds &lt;code&gt;pg_advisory_lock(leader_key)&lt;/code&gt;. Whichever connection acquires it is the leader. Drop the connection and another worker picks it up.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Coordinating expensive, non-transactional side effects.&lt;/strong&gt; Sending an email, calling an external API, regenerating a cache — &lt;code&gt;pg_try_advisory_xact_lock&lt;/code&gt; ensures only one instance does the work.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;what-not-to-use-them-for&quot;&gt;What NOT to use them for&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Replacing row-level locks.&lt;/strong&gt; Use &lt;code&gt;SELECT ... FOR UPDATE&lt;/code&gt; for that. Advisory locks bypass MVCC and don’t protect against your own concurrent transactions writing the same rows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cross-cluster coordination.&lt;/strong&gt; Advisory locks live in one Postgres cluster’s lock table. They mean nothing to replicas, other clusters, or anything outside that one shared memory segment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Anything that should survive a network partition.&lt;/strong&gt; A session that loses its TCP connection has its session-scoped lock released by the postmaster — but only when the backend actually exits, which can take &lt;code&gt;tcp_keepalives_idle + tcp_keepalives_interval × tcp_keepalives_count&lt;/code&gt; (minutes by default).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;the-session-pool-footgun&quot;&gt;The session-pool footgun&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;pg_advisory_lock&lt;/code&gt; is session-scoped. Under PgBouncer &lt;strong&gt;transaction pooling&lt;/strong&gt;, your “session” is one transaction. The lock is released the moment that transaction ends. Use &lt;code&gt;pg_advisory_xact_lock&lt;/code&gt; instead — its lifetime matches the transaction, which is exactly what transaction pooling guarantees you own. This is the most common subtle bug when wiring advisory locks into a pooled application.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;9-buffer-pool-concurrency-briefly&quot;&gt;9. Buffer Pool Concurrency (Briefly)&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;shared_buffers&lt;/code&gt; is one large block of shared memory divided into 8 KB &lt;strong&gt;buffers&lt;/strong&gt;, each of which can hold one page from a table or index. Every backend reads and writes through this pool — there’s no per-backend page cache.&lt;/p&gt;
&lt;p&gt;Concurrency lives at two layers:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The buffer mapping table&lt;/strong&gt; — which buffer holds which page. A central hash table protected by 128 LWLock partitions. Contention here shows up as &lt;code&gt;BufferMapping&lt;/code&gt; waits, usually triggered by very high churn between sets of hot pages and rarely-visited ones.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Per-buffer state&lt;/strong&gt; — a pin count, a content lock (SHARED for read, EXCLUSIVE for write), an “is dirty” flag. Pinning a buffer prevents eviction while a backend is reading from it. Content locks let multiple readers share a page; writers must be alone.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The everyday consequence: &lt;strong&gt;two backends reading the same hot page don’t block each other.&lt;/strong&gt; Two backends writing to the same page do — for the duration of writing one row, which is microseconds. Most “lock contention” stories in Postgres ops chats are actually buffer-content contention, which is a different fix (sort the inserts, partition the table, add a partial index).&lt;/p&gt;
&lt;p&gt;Checkpoints are the other moment when buffer-pool concurrency matters operationally. A &lt;strong&gt;checkpoint&lt;/strong&gt; flushes all dirty buffers to disk. If too many buffers are dirty at once, the I/O storm during the checkpoint causes a latency spike across every query. &lt;code&gt;checkpoint_completion_target&lt;/code&gt; (default 0.9) spreads checkpoint writes over 90% of the interval to smooth this.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;10-decision-tree&quot;&gt;10. Decision Tree&lt;/h2&gt;




























































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Scenario&lt;/th&gt;&lt;th&gt;Reach for&lt;/th&gt;&lt;th&gt;Why&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Many idle clients, few active transactions at any moment&lt;/td&gt;&lt;td&gt;&lt;strong&gt;PgBouncer in transaction pooling&lt;/strong&gt;, backend pool sized to &lt;code&gt;~2× cores&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Multiplexes thousands of clients onto tens of backends. The default modern Postgres deployment shape.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ORM that relies on server-side prepared statements&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Session pooling&lt;/strong&gt; OR PgBouncer ≥ 1.21 with prepared-statement support OR disable server-side prepares in the driver&lt;/td&gt;&lt;td&gt;Transaction pooling breaks server-side prepares unless the pooler emulates them.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Read-heavy analytics that must not block writes&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Read replica&lt;/strong&gt; + async streaming (see &lt;a href=&quot;/blog/postgres-replication/&quot;&gt;replication post&lt;/a&gt;)&lt;/td&gt;&lt;td&gt;Keeps the primary’s snapshot horizon young, prevents long-running readers from blocking vacuum.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Periodic batch job that must not run twice&lt;/td&gt;&lt;td&gt;&lt;strong&gt;&lt;code&gt;pg_advisory_xact_lock(job_id)&lt;/code&gt;&lt;/strong&gt; at the start of the job’s transaction&lt;/td&gt;&lt;td&gt;Single-cluster mutual exclusion that auto-releases on commit/rollback.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Schema migration on a busy table&lt;/td&gt;&lt;td&gt;&lt;strong&gt;&lt;code&gt;SET lock_timeout&lt;/code&gt;&lt;/strong&gt;, then &lt;code&gt;ALTER TABLE ... NOT VALID&lt;/code&gt; / &lt;code&gt;VALIDATE CONSTRAINT&lt;/code&gt;, &lt;strong&gt;&lt;code&gt;CREATE INDEX CONCURRENTLY&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Avoid acquiring &lt;code&gt;ACCESS EXCLUSIVE&lt;/code&gt; for more than the timeout; do the heavy work under weaker locks.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Repeated &lt;code&gt;40001&lt;/code&gt; serialization failures under &lt;code&gt;SERIALIZABLE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Retry with backoff&lt;/strong&gt;, shorten transactions, narrow the rows each transaction touches&lt;/td&gt;&lt;td&gt;SSI assumes you retry. See the &lt;a href=&quot;/blog/acid-properties-and-isolation-levels/&quot;&gt;ACID post&lt;/a&gt; for the retry pattern.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Repeated &lt;code&gt;40P01&lt;/code&gt; deadlocks&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Canonical lock order&lt;/strong&gt; + retry on conflict&lt;/td&gt;&lt;td&gt;Order all multi-row locks the same way across the codebase.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Hot-row contention (a single counter, an inventory total)&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Atomic &lt;code&gt;UPDATE counter = counter + 1&lt;/code&gt;&lt;/strong&gt; at &lt;code&gt;READ COMMITTED&lt;/code&gt;, or shard the counter&lt;/td&gt;&lt;td&gt;Avoid &lt;code&gt;SELECT FOR UPDATE&lt;/code&gt; on a row every request hits.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;idle in transaction&lt;/code&gt; sessions in &lt;code&gt;pg_stat_activity&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;&lt;code&gt;idle_in_transaction_session_timeout&lt;/code&gt;&lt;/strong&gt; + fix the client code&lt;/td&gt;&lt;td&gt;Open transactions just before the writes; close them immediately after.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;LWLock&lt;/code&gt; waits dominate &lt;code&gt;wait_event_type&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Look upstream: too many backends, hot buffer, WAL bottleneck&lt;/td&gt;&lt;td&gt;Not an application fix — usually &lt;code&gt;max_connections&lt;/code&gt; is too high or &lt;code&gt;wal_buffers&lt;/code&gt; is too small.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The pattern: &lt;strong&gt;most concurrency problems are upstream of the database&lt;/strong&gt;. Pool well, hold transactions briefly, lock in consistent order, retry on conflict, and Postgres handles the rest.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;11-common-mistakes&quot;&gt;11. Common Mistakes&lt;/h2&gt;
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Treating &lt;code&gt;max_connections&lt;/code&gt; as a throughput knob.&lt;/strong&gt; It’s a memory ceiling. Going from 200 to 2000 makes things slower, not faster, because every backend competes for the same CPU and same lock table.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Running an ORM with server-side prepared statements through transaction-pooled PgBouncer.&lt;/strong&gt; Symptom: random &lt;code&gt;prepared statement &quot;...&quot; does not exist&lt;/code&gt; errors under load. Fix: disable server-side prepares in the driver, or use a pooler that emulates them.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;No &lt;code&gt;lock_timeout&lt;/code&gt; on migrations.&lt;/strong&gt; Default is zero (infinite). An &lt;code&gt;ALTER TABLE&lt;/code&gt; that can’t get &lt;code&gt;ACCESS EXCLUSIVE&lt;/code&gt; because of one slow &lt;code&gt;SELECT&lt;/code&gt; will sit and block every other query in the meantime. Always &lt;code&gt;SET lock_timeout = &apos;5s&apos;;&lt;/code&gt; before DDL.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Long-running transactions on the primary.&lt;/strong&gt; Each one pins a snapshot and blocks vacuum. Bloat compounds; queries get slower table by table; nobody notices for weeks. Set &lt;code&gt;idle_in_transaction_session_timeout&lt;/code&gt; to something like &lt;code&gt;&apos;5min&apos;&lt;/code&gt;.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Using &lt;code&gt;SERIALIZABLE&lt;/code&gt; without a retry loop.&lt;/strong&gt; SSI aborts conflicting transactions with &lt;code&gt;40001&lt;/code&gt;. Without retry, the application sees random transient errors. (See &lt;a href=&quot;/blog/acid-properties-and-isolation-levels/&quot;&gt;ACID post&lt;/a&gt;.)&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;&lt;code&gt;ALTER TABLE ADD COLUMN ... DEFAULT some_function()&lt;/code&gt; on a hot table.&lt;/strong&gt; Pre-Postgres 11 this rewrote every row under &lt;code&gt;ACCESS EXCLUSIVE&lt;/code&gt;. Modern Postgres handles constant defaults instantly; non-constant defaults still rewrite. Test in staging on representative data.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Acquiring multiple row locks in different orders across code paths.&lt;/strong&gt; Deadlocks under load. Standardize a lock order (alphabetical by primary key, ascending by ID — pick one and document it).&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Forgetting that &lt;code&gt;LISTEN&lt;/code&gt;/&lt;code&gt;NOTIFY&lt;/code&gt; doesn’t survive transaction pooling.&lt;/strong&gt; Symptom: notifications work in dev (direct connection), silently disappear in prod (PgBouncer). Either route LISTEN through session pooling or replace with a real queue.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Using &lt;code&gt;pg_advisory_lock&lt;/code&gt; (session-scoped) under transaction pooling.&lt;/strong&gt; Lock released between transactions whether you wanted it to be or not. Use &lt;code&gt;pg_advisory_xact_lock&lt;/code&gt;.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Treating &lt;code&gt;wait_event = Lock&lt;/code&gt; and &lt;code&gt;wait_event = LWLock&lt;/code&gt; as the same problem.&lt;/strong&gt; First is an application or transaction-ordering issue; second is usually a configuration or workload-shape issue. Different fixes.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Running &lt;code&gt;VACUUM FULL&lt;/code&gt; on a production table during traffic.&lt;/strong&gt; It’s offline (&lt;code&gt;ACCESS EXCLUSIVE&lt;/code&gt;) for as long as it takes to rewrite the table. Use &lt;code&gt;pg_repack&lt;/code&gt; or &lt;code&gt;pg_squeeze&lt;/code&gt; instead.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Holding a transaction open across an HTTP call.&lt;/strong&gt; Common in middleware that wraps the whole request in &lt;code&gt;BEGIN/COMMIT&lt;/code&gt;. Every external call’s latency becomes lock duration for everyone behind you on the same rows.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Adding an index on a frequently-updated column without thinking about HOT.&lt;/strong&gt; Every update now touches the index, costs more, and the column is rarely read by the index anyway. Measure before adding.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Ignoring &lt;code&gt;pg_stat_activity&lt;/code&gt; because “Postgres seems fine.”&lt;/strong&gt; It’s the cheapest production diagnostic in the stack. Make it one query away from being on a dashboard.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;12-closing&quot;&gt;12. Closing&lt;/h2&gt;
&lt;p&gt;The number of concurrent clients your database supports isn’t &lt;code&gt;max_connections&lt;/code&gt;. Backends are bounded by your CPU cores; clients are bounded by how briefly each one actually needs the database. Pool well and a handful of backends serves thousands of clients. The lock manager keeps writers correct; MVCC keeps readers fast; vacuum keeps the past garbage-collected; deadlock detection keeps cycles short; &lt;code&gt;pg_stat_activity&lt;/code&gt; tells you which of those failed.&lt;/p&gt;
&lt;p&gt;The skill is recognizing which layer a slowdown lives in. Connection-saturation, heavyweight-lock contention, internal-LWLock contention, MVCC bloat, plain old disk I/O — these look identical to the application (“the database is slow”) and have completely different fixes. The diagnostic queries in section 7 are the difference between “we’re rolling back the deploy” and “we know exactly which transaction is holding everyone up.”&lt;/p&gt;
&lt;p&gt;The next post in the Database Internals series steps back to the operational layer: &lt;strong&gt;configuration, observability, and the production checklist&lt;/strong&gt; — the settings, dashboards, and alerts that turn the everything-above into something you can run at 3 AM.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;related-reading&quot;&gt;Related reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/acid-properties-and-isolation-levels/&quot;&gt;ACID, Read Phenomena, and Isolation Levels&lt;/a&gt; — the semantic layer this post implements. Read first if you’re new to isolation.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/db-storage-and-indexing/&quot;&gt;How Databases Actually Store and Find Your Data&lt;/a&gt; — what a tuple physically is on disk; the substrate for MVCC.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/postgres-replication/&quot;&gt;Database Replication&lt;/a&gt; — concurrency across nodes; read replicas as a release valve for long-running readers.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/postgres-indexing/&quot;&gt;PostgreSQL Indexing Deep Dive&lt;/a&gt; — &lt;code&gt;CREATE INDEX CONCURRENTLY&lt;/code&gt; and the lock modes it acquires, in depth.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/postgres-partitioning/&quot;&gt;Postgres Partitioning&lt;/a&gt; — partition-level locking and how it interacts with autovacuum on huge tables.&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Database Replication: Strategies, Topologies, and What to Use When</title><link>https://abhimanyunagurkar.com/blog/postgres-replication/</link><guid isPermaLink="true">https://abhimanyunagurkar.com/blog/postgres-replication/</guid><description>A practical guide to PostgreSQL replication — physical vs logical, sync vs async, single-leader / multi-leader / leaderless, and replica-read rules.</description><pubDate>Fri, 15 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Every serious database supports replication. The configuration options sound similar across systems — &lt;em&gt;primary&lt;/em&gt;, &lt;em&gt;replica&lt;/em&gt;, &lt;em&gt;sync&lt;/em&gt;, &lt;em&gt;async&lt;/em&gt;, &lt;em&gt;logical&lt;/em&gt;, &lt;em&gt;physical&lt;/em&gt;, &lt;em&gt;quorum&lt;/em&gt; — but the choices you make under those names determine how your application behaves when things break. Replication is where database internals leak into application design: the difference between a write being “durable” and “durable enough to survive the primary going down” is the difference between losing one transaction and losing fifteen minutes of orders.&lt;/p&gt;
&lt;p&gt;This post walks through how replication actually works in PostgreSQL, the topology and consistency choices you’ll have to make, and a decision tree for picking what to use when. We’ll stick to Postgres for code, but the patterns transfer to MySQL, MongoDB, and most other systems with minor adjustments.&lt;/p&gt;
&lt;p&gt;This is Part 2 of the Distributed Systems series. Part 1 covered &lt;a href=&quot;/blog/postgres-sharding/&quot;&gt;sharding&lt;/a&gt;, and assumed you understood replication well enough to design the migration path. If that section felt fast, this is where it slows down.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;1-why-replicate&quot;&gt;1. Why Replicate&lt;/h2&gt;
&lt;p&gt;Five reasons, in roughly the order they show up as a system grows.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;High availability.&lt;/strong&gt; The primary dies — the replica is promoted and serves traffic. Without a replica, you’re restoring from backup and apologizing to users for an hour.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Read scaling.&lt;/strong&gt; Analytics dashboards, reporting jobs, and bulk exports run against replicas instead of competing with transactional traffic on the primary.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Geographic distribution.&lt;/strong&gt; A replica in another region serves local reads at 5ms instead of 150ms across the ocean.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Disaster recovery.&lt;/strong&gt; A replica in another data centre (or another cloud) means a fire, a misconfiguration, or a deletion in one location doesn’t end your business.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Major-version upgrades.&lt;/strong&gt; Logical replication lets you stream from a Postgres 14 primary to a Postgres 17 replica, then cut over with seconds of downtime. The alternative is &lt;code&gt;pg_upgrade&lt;/code&gt; with hours of downtime, and a much scarier rollback story.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most teams reach for replication for HA first, then add read replicas as they grow, then geography when international users complain.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;2-the-vocabulary&quot;&gt;2. The Vocabulary&lt;/h2&gt;
&lt;p&gt;Before any setup, the words. A lot of replication confusion comes from these terms being used loosely.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Primary&lt;/strong&gt; (or &lt;em&gt;leader&lt;/em&gt;, &lt;em&gt;master&lt;/em&gt; in older docs) — the node that accepts writes. Postgres has exactly one primary per cluster. The modern term is &lt;em&gt;primary&lt;/em&gt;; &lt;em&gt;master&lt;/em&gt; is being phased out across most projects.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Replica&lt;/strong&gt; (or &lt;em&gt;standby&lt;/em&gt;, &lt;em&gt;follower&lt;/em&gt;, &lt;em&gt;secondary&lt;/em&gt;) — a node that receives the primary’s changes and applies them locally. May or may not serve reads, depending on configuration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Write-Ahead Log (WAL)&lt;/strong&gt; — Postgres writes every change to the WAL before applying it to the heap. Replication, at its core, is “ship the WAL from primary to replica, and replay it there.”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Replication lag&lt;/strong&gt; — how far behind the replica is, measured either in &lt;strong&gt;bytes&lt;/strong&gt; (how much WAL hasn’t been applied yet) or &lt;strong&gt;time&lt;/strong&gt; (how long ago the latest applied transaction happened on the primary). Lag is almost always non-zero in async setups.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Synchronous vs asynchronous&lt;/strong&gt; — does the primary wait for the replica to acknowledge each commit before returning success to the client? Sync = wait (safer, slower). Async = don’t wait (faster, you may lose committed data on a primary crash).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Physical replication&lt;/strong&gt; — replicas are byte-for-byte copies of the primary at the storage level. The WAL is shipped and replayed as-is. Same Postgres version on both sides required.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Logical replication&lt;/strong&gt; — replicas receive &lt;em&gt;row changes&lt;/em&gt; (&lt;code&gt;INSERT&lt;/code&gt;, &lt;code&gt;UPDATE&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt;) decoded from the WAL, not raw byte changes. The replica can be a different Postgres major version, a different schema (with caveats), or even a different database system.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Topology&lt;/strong&gt; — the shape of the replication relationships. Single-leader (one primary, many replicas), multi-leader (multiple primaries replicating to each other), or leaderless (no designated primary).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Quorum&lt;/strong&gt; — a write or read is considered successful if it’s acknowledged by a majority (or some configured threshold) of nodes. Used in leaderless systems and in Postgres synchronous-with-N configurations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Consistency model&lt;/strong&gt; — what a client can observe across reads after a write. Strong / linearizable means “as if there’s one machine.” Eventual means “you’ll see it eventually.” More nuance in Section 6.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;3-the-three-real-replication-strategies&quot;&gt;3. The Three Real Replication Strategies&lt;/h2&gt;
&lt;p&gt;There are technically four ways databases replicate. Three of them matter.&lt;/p&gt;
&lt;h3 id=&quot;statement-based-historical-mostly-avoided&quot;&gt;Statement-based (historical, mostly avoided)&lt;/h3&gt;
&lt;p&gt;The primary writes a log of every SQL statement; replicas replay them. MySQL’s original replication worked this way.&lt;/p&gt;
&lt;p&gt;Problem: non-deterministic statements. &lt;code&gt;INSERT INTO logs (id, created_at) VALUES (DEFAULT, NOW())&lt;/code&gt; produces different results on every machine. Same with &lt;code&gt;RAND()&lt;/code&gt;, &lt;code&gt;UUID()&lt;/code&gt;, statements with &lt;code&gt;LIMIT&lt;/code&gt; and no &lt;code&gt;ORDER BY&lt;/code&gt;, and anything depending on table contents. You end up with replicas that silently diverge.&lt;/p&gt;
&lt;p&gt;Postgres has never used statement-based replication. MySQL moved away from it as the default in 5.6+. If your database advertises “SQL replication,” investigate carefully — you’re almost certainly looking at this category.&lt;/p&gt;
&lt;h3 id=&quot;physical--wal-streaming-postgres-default&quot;&gt;Physical / WAL Streaming (Postgres default)&lt;/h3&gt;
&lt;p&gt;The primary streams its raw WAL records to the replica. The replica writes them to disk and replays them, producing a byte-for-byte identical copy of the primary’s storage.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ini&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# postgresql.conf on the primary&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;wal_level&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; = replica            &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# WAL detail level (replica is enough for streaming)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;max_wal_senders&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; = 10           &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# how many concurrent replicas can stream&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;max_replication_slots&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; = 10     &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# slots reserved for replicas&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# On the new replica machine: clone the primary&apos;s data directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;pg_basebackup&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -h&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; primary.internal&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -U&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; replicator&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -D&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; /var/lib/postgresql/data&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  -P&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -R&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -X&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; stream&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# pg_basebackup with -R creates standby.signal and configures&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# primary_conninfo, so the replica starts up and immediately&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# starts streaming.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; the default for HA and read replicas. It’s fast, low-overhead, and supports streaming replication of every operation including &lt;code&gt;DDL&lt;/code&gt; (Data Definition Language — &lt;code&gt;ALTER TABLE&lt;/code&gt;, &lt;code&gt;CREATE INDEX&lt;/code&gt;, etc.).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When not to use:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Replica needs to be a different Postgres major version → use logical instead.&lt;/li&gt;
&lt;li&gt;Replica needs a different schema (some tables only, transformed columns) → use logical.&lt;/li&gt;
&lt;li&gt;Replicating between Postgres and a different database system → not possible with physical.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;logical-replication-publication--subscription&quot;&gt;Logical Replication (publication / subscription)&lt;/h3&gt;
&lt;p&gt;The primary’s WAL is decoded into a stream of row-level changes (&lt;code&gt;row INSERTED into orders&lt;/code&gt;, &lt;code&gt;column updated on users.id=42&lt;/code&gt;) which subscribers consume. Subscribers can be different Postgres versions, different schemas, or external systems.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- on the primary (publisher)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ALTER&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; SYSTEM&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; SET&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; wal_level &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;logical&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;   &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- requires a restart&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pg_reload_conf();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; PUBLICATION app_pub &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FOR&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; TABLE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; users, orders, payments;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- or: CREATE PUBLICATION all_pub FOR ALL TABLES;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- on the replica (subscriber)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; SUBSCRIPTION app_sub&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  CONNECTION&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;host=primary.internal dbname=app user=replicator password=...&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  PUBLICATION app_pub;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the subscription is created, Postgres performs an initial table copy, then streams ongoing changes. Lag is visible in &lt;code&gt;pg_stat_subscription&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Major-version upgrades (PG 14 → PG 17 with no downtime).&lt;/li&gt;
&lt;li&gt;Replicating a subset of tables (instead of the whole cluster).&lt;/li&gt;
&lt;li&gt;Streaming changes to non-Postgres systems (Debezium reads logical replication slots and emits to Kafka).&lt;/li&gt;
&lt;li&gt;Cross-database migrations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;When not to use:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HA — you want physical streaming for that.&lt;/li&gt;
&lt;li&gt;Replicating DDL changes — logical replication doesn’t carry schema changes. You apply them on both sides manually or with tooling.&lt;/li&gt;
&lt;li&gt;Replicating sequences — they’re not replicated. You manage them out-of-band during cutover.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;trigger-based-last-resort-application-level&quot;&gt;Trigger-based (last-resort, application-level)&lt;/h3&gt;
&lt;p&gt;Triggers on every table capture changes into a queue, which an application process consumes. Slonik and Bucardo are the classic examples. Useful before logical replication existed (pre-Postgres 10); rarely the right answer today.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;4-sync-modes--the-latency--durability-trade&quot;&gt;4. Sync Modes — The Latency / Durability Trade&lt;/h2&gt;
&lt;p&gt;Replication is a stream by default — the primary doesn’t wait for replicas to acknowledge anything. That’s fine for most workloads. When zero data loss matters (financial transactions, audit logs), you make it synchronous.&lt;/p&gt;
&lt;p&gt;Postgres exposes this via &lt;code&gt;synchronous_commit&lt;/code&gt; and &lt;code&gt;synchronous_standby_names&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ini&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# postgresql.conf on the primary&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Which replicas count as synchronous, and how many must ack&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;synchronous_standby_names&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;ANY 2 (replica1, replica2, replica3)&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# What &quot;ack&quot; means at commit time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;synchronous_commit&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;on&apos;&lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;         # default&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;synchronous_commit&lt;/code&gt; has five levels, ordered from fastest-and-riskiest to safest-and-slowest:&lt;/p&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Level&lt;/th&gt;&lt;th&gt;Primary returns success when…&lt;/th&gt;&lt;th&gt;You lose on a primary crash&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;off&lt;/code&gt;&lt;/td&gt;&lt;td&gt;WAL is in memory, not yet on disk&lt;/td&gt;&lt;td&gt;Last few transactions, even on local disk&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;local&lt;/code&gt;&lt;/td&gt;&lt;td&gt;WAL is fsync’d on the primary&lt;/td&gt;&lt;td&gt;Nothing locally; replicas may lag&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;remote_write&lt;/code&gt;&lt;/td&gt;&lt;td&gt;WAL is received by the replica’s memory&lt;/td&gt;&lt;td&gt;Tiny window if replica also crashes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;on&lt;/code&gt; (default)&lt;/td&gt;&lt;td&gt;WAL is fsync’d on the replica’s disk&lt;/td&gt;&lt;td&gt;Effectively zero data loss on failover&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;remote_apply&lt;/code&gt;&lt;/td&gt;&lt;td&gt;WAL is &lt;em&gt;applied&lt;/em&gt; on the replica (rows visible)&lt;/td&gt;&lt;td&gt;Zero — replica is fully caught up&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The cost of moving up this ladder is latency. Every commit now includes a round-trip to the replica. A &lt;code&gt;remote_apply&lt;/code&gt; setup with a replica in another region adds ~10–50ms to &lt;em&gt;every&lt;/em&gt; write transaction. That’s fine for a billing system; catastrophic for a high-write event ingestion service.&lt;/p&gt;
&lt;p&gt;The pragmatic answer most teams settle on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Default to async&lt;/strong&gt; (&lt;code&gt;synchronous_commit = local&lt;/code&gt;) for typical workloads.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;remote_write&lt;/code&gt; with one nearby replica&lt;/strong&gt; when you want HA with low write latency.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;on&lt;/code&gt; or &lt;code&gt;remote_apply&lt;/code&gt; with a quorum (&lt;code&gt;ANY 2 (...)&lt;/code&gt;)&lt;/strong&gt; for genuinely-can’t-lose-this data, with multiple replicas so any one can ack without blocking.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Two-replica gotcha:&lt;/strong&gt; &lt;code&gt;synchronous_standby_names = &apos;FIRST 1 (r1, r2)&apos;&lt;/code&gt; means “always wait for r1 specifically.” If r1 dies, all your writes block. Use &lt;code&gt;ANY 1 (r1, r2)&lt;/code&gt; to allow either replica to ack — much better availability profile.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;5-topologies--single-leader-multi-leader-leaderless&quot;&gt;5. Topologies — Single-Leader, Multi-Leader, Leaderless&lt;/h2&gt;
&lt;p&gt;The shape of who-replicates-to-whom. Three families.&lt;/p&gt;
&lt;h3 id=&quot;single-leader-95-of-systems&quot;&gt;Single-Leader (95% of systems)&lt;/h3&gt;
&lt;p&gt;One primary accepts all writes. N replicas receive changes. Reads can come from either, with consistency caveats.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              ┌──────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              │ Primary  │  ← all writes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              └────┬─────┘&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            WAL ───┼───────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              ┌────▼─────┐ │ ┌──────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              │ Replica1 │ └─► Replica2 │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              └──────────┘   └──────────┘&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                  ▲              ▲&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              reads          reads&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Strengths:&lt;/strong&gt; simple to reason about, no write conflicts, vanilla Postgres supports it natively, every transactional guarantee you’re used to still holds.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Weaknesses:&lt;/strong&gt; the primary is a single point of failure for &lt;em&gt;writes&lt;/em&gt;. Failover takes seconds to minutes (until a replica is promoted). Writes can’t be served from multiple regions simultaneously.&lt;/p&gt;
&lt;p&gt;This is what your Postgres setup is using today unless you’ve actively configured otherwise. Use it until you have a specific reason not to.&lt;/p&gt;
&lt;h3 id=&quot;multi-leader&quot;&gt;Multi-Leader&lt;/h3&gt;
&lt;p&gt;Two or more primaries, each accepting writes, replicating to each other.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   ┌──────────┐         ┌──────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   │ Primary  │◄───────►│ Primary  │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   │   us     │  bi-dir │   eu     │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   └──────────┘         └──────────┘&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        ▲                    ▲&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     writes               writes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Useful when writes need to be served close to users in multiple regions, or for active-active disaster recovery.&lt;/p&gt;
&lt;p&gt;The hard part is &lt;strong&gt;conflict resolution&lt;/strong&gt;. If &lt;code&gt;us&lt;/code&gt; and &lt;code&gt;eu&lt;/code&gt; both update &lt;code&gt;users.email&lt;/code&gt; for the same row at roughly the same time, which one wins? Standard strategies:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Last-write-wins&lt;/strong&gt; — keep the update with the latest timestamp. Simple, but you silently drop one of the writes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Application-defined merge&lt;/strong&gt; — application sees both versions and picks. Works for additive structures (sets, counters via CRDTs).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Region-pinned writes&lt;/strong&gt; — each row is “owned” by one region, only that region writes to it. Avoids conflicts by design but loses some of the locality benefit.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Postgres in this space:&lt;/strong&gt; core Postgres doesn’t support multi-leader replication. The mature options are extensions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.pgedge.com/&quot;&gt;pgEdge&lt;/a&gt;&lt;/strong&gt; (formerly EDB BDR) — commercial distributed Postgres with built-in multi-master and conflict resolution.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;pgactive&lt;/strong&gt; — AWS’s open-source fork of BDR, used inside RDS Multi-AZ for active-active.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Citus&lt;/strong&gt; — primarily a sharding extension but supports some multi-master patterns through its coordinator.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The honest read: multi-leader Postgres is a niche, expert-only configuration. Most teams that think they need it actually need single-leader with regional read replicas — writes go cross-region to the primary, reads stay local.&lt;/p&gt;
&lt;h3 id=&quot;leaderless&quot;&gt;Leaderless&lt;/h3&gt;
&lt;p&gt;No designated primary. Any node can accept writes and any node can serve reads. Writes are sent to multiple nodes in parallel; reads are also sent to multiple nodes and the most recent wins.&lt;/p&gt;
&lt;p&gt;This is the &lt;a href=&quot;https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf&quot;&gt;Dynamo&lt;/a&gt; model — Cassandra, ScyllaDB, DynamoDB, Riak all use variants of it.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       ┌─────────┐  ┌─────────┐  ┌─────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       │ Node A  │  │ Node B  │  │ Node C  │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       └─────────┘  └─────────┘  └─────────┘&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            ▲            ▲            ▲&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            └────────────┼────────────┘&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                  any node accepts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                   reads and writes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The consistency knob is the &lt;strong&gt;R + W &gt; N&lt;/strong&gt; rule:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;N&lt;/code&gt; = total replicas of each piece of data.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;W&lt;/code&gt; = how many replicas must acknowledge a write.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;R&lt;/code&gt; = how many replicas must respond to a read.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If &lt;code&gt;R + W &gt; N&lt;/code&gt;, the read and write quorums overlap by at least one node — so any read is guaranteed to see at least one node that has the latest write. That’s how leaderless systems give you “tunable consistency” without a primary.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Common configurations:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  N=3, W=2, R=2  →  strong-ish reads, can tolerate 1 node down&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  N=3, W=3, R=1  →  fast reads, slower writes, can&apos;t tolerate write-side failures&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  N=3, W=1, R=1  →  fastest possible, eventual consistency only&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Conflict resolution&lt;/strong&gt; still has to happen. Leaderless systems usually attach a version vector or timestamp to every write and use last-write-wins (sometimes vector clocks for more correctness).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Postgres in this space:&lt;/strong&gt; Postgres does &lt;strong&gt;not&lt;/strong&gt; natively do leaderless replication. The model is fundamentally incompatible with Postgres’s strict serializability and ACID transactions. If you need leaderless, you’re using Cassandra, DynamoDB, ScyllaDB, or similar — not Postgres.&lt;/p&gt;
&lt;p&gt;Worth knowing about anyway because:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Production systems often pair Postgres for transactional data with a leaderless store for high-write event data (session state, feature flags, telemetry). Knowing both models lets you pick the right tool.&lt;/li&gt;
&lt;li&gt;The R+W&gt;N idea is portable — it shows up in custom consensus protocols, in CRDTs, and in some edge-caching strategies.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&quot;6-consistency-models-in-plain-language&quot;&gt;6. Consistency Models in Plain Language&lt;/h2&gt;
&lt;p&gt;Replication is when consistency models stop being academic and start being a bug in your application. Five worth knowing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Strong consistency / linearizability.&lt;/strong&gt; Reads always see the most recent committed write, as if there’s only one machine. Single-node Postgres gives you this for free. Across replicas, you get it only if you always read from the primary, or use synchronous replication with &lt;code&gt;remote_apply&lt;/code&gt;, or use a system with consensus (Raft) baked in. &lt;em&gt;You’d notice this when:&lt;/em&gt; you don’t notice it. Things just work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Eventual consistency.&lt;/strong&gt; Reads may return stale data, but if writes stop, all replicas eventually converge. Default for async replication. &lt;em&gt;You’d notice this when:&lt;/em&gt; a user updates their profile, refreshes the page, and sees the old value because the page hit a replica that hasn’t caught up.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Read-your-writes consistency.&lt;/strong&gt; A given user always sees their own writes immediately, even if other users might see stale data. Stronger than eventual, weaker than strong. &lt;em&gt;You’d notice this when:&lt;/em&gt; you implement this poorly and a user’s “Save” button appears to do nothing on refresh — the most common cause of users repeatedly clicking Save and producing duplicates.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Monotonic reads.&lt;/strong&gt; Once a user has seen a particular write, they will not see any earlier state of that data on a subsequent read, even if they hit a different replica. Prevents the “looks like it went backwards” experience. &lt;em&gt;You’d notice this when:&lt;/em&gt; a user sees their order in the order list, refreshes, and it disappears because the second read hit a less-caught-up replica.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bounded staleness.&lt;/strong&gt; Reads may be stale, but never by more than &lt;code&gt;X&lt;/code&gt; seconds or &lt;code&gt;Y&lt;/code&gt; transactions. Useful when “freshness within 5 seconds” is acceptable but “minutes-old data” is not. &lt;em&gt;You’d notice this when:&lt;/em&gt; you intentionally configure it to keep dashboards responsive without making them outright wrong.&lt;/p&gt;
&lt;p&gt;Strong consistency is the safest default. Every weakening is something the application has to handle. Most production systems land on &lt;em&gt;eventual consistency with read-your-writes and monotonic reads&lt;/em&gt; — the application is allowed to see slightly stale data from other users’ updates, but always sees its own writes correctly.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;7-replica-reads--the-rules&quot;&gt;7. Replica Reads — The Rules&lt;/h2&gt;
&lt;p&gt;Reading from replicas is the most common way teams hurt themselves with replication. The lag is real, the application usually ignores it, and the bugs are subtle.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When stale data is fine:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Analytics dashboards (a 10-second-old aggregate is indistinguishable from a current one).&lt;/li&gt;
&lt;li&gt;Recommendation systems (the model doesn’t update that often anyway).&lt;/li&gt;
&lt;li&gt;Search results.&lt;/li&gt;
&lt;li&gt;Public-facing read-only views (blog posts, product catalogs, documentation).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;When stale data is not fine:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Anything immediately after a write by the same user (“did my comment post?”).&lt;/li&gt;
&lt;li&gt;Authorization checks (“does this user still have admin access?”).&lt;/li&gt;
&lt;li&gt;Inventory or financial decisions (“does this user have funds?”).&lt;/li&gt;
&lt;li&gt;Any read that drives a subsequent write decision.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Four patterns for handling this:&lt;/p&gt;
&lt;h3 id=&quot;pattern-1-read-primary-after-write&quot;&gt;Pattern 1: Read primary after write&lt;/h3&gt;
&lt;p&gt;The simplest correct approach. After a write, the same request reads from the primary, not a replica. The application explicitly tracks which connection to use.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# pseudocode&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; update_profile&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(user_id, changes):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    with&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; primary_db.transaction() &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; tx:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        tx.execute(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;UPDATE users SET ... WHERE id = ?&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, user_id, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;        # Read from primary for the rest of this request&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; tx.execute(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;SELECT * FROM users WHERE id = ?&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, user_id)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Strength:&lt;/strong&gt; rock solid. &lt;strong&gt;Weakness:&lt;/strong&gt; offloads no reads to replicas during write-paths.&lt;/p&gt;
&lt;h3 id=&quot;pattern-2-sticky-sessions&quot;&gt;Pattern 2: Sticky sessions&lt;/h3&gt;
&lt;p&gt;A user’s session is bound to a specific replica (or to the primary) for some window after a write. Used in larger systems with many replicas — keeps things consistent for that user without sending all their traffic to the primary.&lt;/p&gt;
&lt;h3 id=&quot;pattern-3-lsn-tracking-read-your-writes&quot;&gt;Pattern 3: LSN tracking (read-your-writes)&lt;/h3&gt;
&lt;p&gt;After a write on the primary, you record the &lt;strong&gt;Log Sequence Number (LSN)&lt;/strong&gt; — Postgres’s monotonically-increasing position in the WAL. On the next read, you pass the LSN; the replica delays the query (or routes to primary) until it has replayed up to that LSN.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- after a write on the primary, record the LSN&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pg_current_wal_lsn();          &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- e.g., &apos;0/3001028&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- on the replica side, wait until that LSN has been applied&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pg_wal_replay_wait(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;0/3001028&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;timeout&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;500ms&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ...                            &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- now safe to query&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the closest thing to “always see your own writes” without sending all reads to the primary. It’s slightly more code but cleaner than sticky sessions.&lt;/p&gt;
&lt;h3 id=&quot;pattern-4-read-only-replica-with-a-freshness-contract&quot;&gt;Pattern 4: Read-only replica with a freshness contract&lt;/h3&gt;
&lt;p&gt;Document explicitly which workloads are allowed to use the replica (analytics, exports, reports) and which must use the primary (anything user-facing immediately after a write). Enforce in code via separate connection pools — &lt;code&gt;primary_pool&lt;/code&gt; and &lt;code&gt;replica_pool&lt;/code&gt; — and require any new query to be reviewed against the contract.&lt;/p&gt;
&lt;p&gt;This is what most production teams settle on. It’s not magic; it’s just “be deliberate.”&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;8-postgres-replication-end-to-end&quot;&gt;8. Postgres Replication, End to End&lt;/h2&gt;
&lt;p&gt;Putting it together. A canonical HA setup looks like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                ┌──────────────────────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                │     Application tier     │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                └──────────────┬───────────┘&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                           pgbouncer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                ┌──────────────┴───────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                │  Patroni-managed Postgres │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                │                          │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                │   ┌──────────────────┐   │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                │   │  Primary         │   │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                │   │  (accepts writes)│   │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                │   └────────┬─────────┘   │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                │            │ WAL stream  │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                │   ┌────────▼─────────┐   │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                │   │  Standby #1      │   │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                │   │  sync replica    │   │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                │   └──────────────────┘   │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                │   ┌────────▼─────────┐   │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                │   │  Standby #2      │   │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                │   │  async replica   │   │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                │   │  serves reads    │   │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                │   └──────────────────┘   │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                └──────────────────────────┘&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The pieces:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Patroni&lt;/strong&gt; (or Stolon) — automated failover manager. Watches the primary’s health, promotes a standby when needed, reconfigures pgbouncer or DNS so the application reconnects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;pgbouncer&lt;/strong&gt; — connection pooler. Important not just for connection economy but because it handles the brief disconnect during failover gracefully.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sync replica (#1)&lt;/strong&gt; — close-network replica with &lt;code&gt;synchronous_commit = on&lt;/code&gt;. Guarantees zero data loss on failover.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Async replica (#2)&lt;/strong&gt; — further from the primary, lag is allowed. Handles read traffic, also a candidate for promotion in cross-region disaster scenarios.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Monitoring lag&lt;/strong&gt; is non-negotiable. On the primary:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  application_name,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  state&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  pg_wal_lsn_diff(pg_current_wal_lsn(), sent_lsn)   &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;AS&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pending_bytes,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  pg_wal_lsn_diff(sent_lsn, write_lsn)              &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;AS&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; write_lag_bytes,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  pg_wal_lsn_diff(write_lsn, flush_lsn)             &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;AS&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; flush_lag_bytes,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  pg_wal_lsn_diff(flush_lsn, replay_lsn)            &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;AS&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; replay_lag_bytes,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  write_lag,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  flush_lag,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  replay_lag&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pg_stat_replication;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Alert on &lt;code&gt;replay_lag&lt;/code&gt; exceeding your SLA. A common threshold: anything over 30 seconds on a standby that serves reads triggers a page; anything over 5 minutes on any standby triggers an investigation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Failover testing&lt;/strong&gt; is the difference between a system that fails over and a system that &lt;em&gt;advertises&lt;/em&gt; it can fail over. The expected discipline:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Do a controlled failover every quarter.&lt;/li&gt;
&lt;li&gt;Time it. Verify the application reconnects.&lt;/li&gt;
&lt;li&gt;Verify replica lag was zero at the moment of promotion (otherwise you’ve lost data).&lt;/li&gt;
&lt;li&gt;Document the recovery time and any rough edges.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Teams that don’t do this discover during the actual outage that their Patroni config was subtly wrong, or that pgbouncer didn’t refresh DNS, or that one application server didn’t reconnect cleanly.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;9-decision-tree&quot;&gt;9. Decision Tree&lt;/h2&gt;













































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;What you need&lt;/th&gt;&lt;th&gt;Use&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;HA against primary loss, single region&lt;/td&gt;&lt;td&gt;Single-leader, async streaming, &lt;strong&gt;Patroni&lt;/strong&gt; for failover&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;HA with zero-data-loss tolerance&lt;/td&gt;&lt;td&gt;Single-leader with &lt;code&gt;synchronous_commit = on&lt;/code&gt;, &lt;code&gt;ANY N&lt;/code&gt; quorum across ≥ 2 nearby replicas&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Read scaling for reports / analytics&lt;/td&gt;&lt;td&gt;Async streaming replicas, route OLAP traffic via separate connection pool&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Major-version upgrade with seconds of downtime&lt;/td&gt;&lt;td&gt;Logical replication PG-old → PG-new, application cutover&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Replicate a subset of tables to another system&lt;/td&gt;&lt;td&gt;Logical replication + Debezium / CDC&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Cross-region active-active writes&lt;/td&gt;&lt;td&gt;Multi-leader (pgEdge / pgactive) — or rethink with regional read replicas + cross-region primary&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;High-write event data, no transactions needed&lt;/td&gt;&lt;td&gt;Leaderless DB (Cassandra / DynamoDB) — not Postgres&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Strict read-your-writes after a user action&lt;/td&gt;&lt;td&gt;Read from primary, or LSN tracking via &lt;code&gt;pg_wal_replay_wait&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Globally-consistent reporting&lt;/td&gt;&lt;td&gt;Read primary only, or use synchronous quorum + read from sync replica&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&quot;10-common-mistakes-checklist&quot;&gt;10. Common Mistakes Checklist&lt;/h2&gt;
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Treating replicas as backups. Replicas mirror corruption and accidental &lt;code&gt;DELETE&lt;/code&gt;s in real time. You still need &lt;code&gt;pg_basebackup&lt;/code&gt; + WAL archives.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Reading from replicas in a write-then-read flow without thinking about lag. Save button appears to “not work.”&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Synchronous commit on every replica. Latency dies; one slow replica blocks all writes.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;code&gt;synchronous_standby_names = &apos;FIRST 1 (r1)&apos;&lt;/code&gt; instead of &lt;code&gt;&apos;ANY 1 (r1, r2)&apos;&lt;/code&gt;. If r1 dies, writes block.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; No failover automation. Manual failover during a 3 AM outage takes 30+ minutes; automated takes 30 seconds.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Untested failover. The first real failover discovers the bug.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; No lag monitoring. You find out the replica is hours behind because someone queried it for a report.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Multi-leader without a conflict-resolution strategy. Data silently diverges.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Letting application code use &lt;code&gt;primary_pool&lt;/code&gt; and &lt;code&gt;replica_pool&lt;/code&gt; interchangeably. Subtle bugs from stale reads everywhere.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Forgetting that logical replication doesn’t carry DDL. Schema changes have to be applied to both sides manually.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Forgetting that sequences aren’t replicated by logical replication. After cutover, your &lt;code&gt;bigserial&lt;/code&gt; columns start at 1.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;11-closing&quot;&gt;11. Closing&lt;/h2&gt;
&lt;p&gt;Replication is one of those topics where the building blocks are straightforward but every combination has a real-world implication. Single-leader async streaming is the right answer 95% of the time. Logical replication is the right answer for version upgrades and CDC. Multi-leader and leaderless are real but rare, and worth understanding mostly so you can recognize when someone is reaching for them prematurely.&lt;/p&gt;
&lt;p&gt;The skill isn’t memorizing which knob does what. It’s developing the instinct for “where would lag show up here?” before you ship the feature — because every replicated database has lag, and every async system can lose its most recent writes, and the application either accounts for that or doesn’t.&lt;/p&gt;
&lt;p&gt;Next in the Distributed Systems series: &lt;strong&gt;consensus protocols&lt;/strong&gt;. When you need stronger guarantees than single-leader async can give you — distributed transactions that actually commit atomically, or leader election that doesn’t split-brain — you reach for Raft or Paxos. We’ll walk through what they actually do, why they’re hard, and where you find them in production (etcd, Consul, CockroachDB, every modern distributed system you can name).&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;related-reading&quot;&gt;Related reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/postgres-sharding/&quot;&gt;Sharding Postgres: When One Database Stops Being Enough&lt;/a&gt; — Part 1 of this series; the architectural step that often precedes thinking about replication topology.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/postgres-partitioning/&quot;&gt;Postgres Partitioning: Strategies, Advantages, and Pitfalls&lt;/a&gt; — how partitioning interacts with WAL streaming and logical replication.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/acid-properties-and-isolation-levels/&quot;&gt;ACID, Read Phenomena, and Isolation Levels&lt;/a&gt; — the local-transaction guarantees that replication is trying (or not trying) to preserve.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/postgres-indexing/&quot;&gt;PostgreSQL Indexing Deep Dive&lt;/a&gt; — relevant when designing replica-only read workloads and partial-index reads against followers.&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Postgres Partitioning: Strategies, Real Advantages, and Pitfalls</title><link>https://abhimanyunagurkar.com/blog/postgres-partitioning/</link><guid isPermaLink="true">https://abhimanyunagurkar.com/blog/postgres-partitioning/</guid><description>A practical guide to PostgreSQL partitioning — RANGE, LIST, HASH, pruning, local indexes, real advantages, and the pitfalls that bite in production.</description><pubDate>Wed, 13 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The &lt;code&gt;events&lt;/code&gt; table is now 4 TB. Queries that used to be milliseconds are seconds. &lt;code&gt;autovacuum&lt;/code&gt; (the background process that reclaims space from dead row versions left behind by &lt;code&gt;UPDATE&lt;/code&gt; and &lt;code&gt;DELETE&lt;/code&gt;) is permanently behind. The primary-key index doesn’t fit in &lt;code&gt;shared_buffers&lt;/code&gt; (Postgres’s in-memory cache for table and index pages, sized at startup). The nightly &lt;code&gt;DELETE FROM events WHERE created_at &amp;#x3C; ...&lt;/code&gt; runs into morning traffic and barely reclaims any disk space anyway.&lt;/p&gt;
&lt;p&gt;You haven’t outgrown one machine. The CPU is fine, the RAM is fine, the disk has headroom. The &lt;em&gt;table&lt;/em&gt; has outgrown the assumptions Postgres makes about a single relation. This is the problem partitioning is for.&lt;/p&gt;
&lt;p&gt;This post walks through how partitioning works in Postgres, the advantages it actually delivers (some non-obvious), and the pitfalls that bite teams in production. When you’re done, you should know whether your workload needs partitioning, which strategy to pick, and which mistakes to plan around.&lt;/p&gt;
&lt;p&gt;This is Part 7 of the Database Internals series. Earlier parts covered indexing, B-trees, and EXPLAIN — all relevant context here.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;1-what-partitioning-actually-is&quot;&gt;1. What Partitioning Actually Is&lt;/h2&gt;
&lt;p&gt;Partitioning is &lt;strong&gt;horizontal decomposition of one logical table into multiple physical tables that live in the same Postgres cluster&lt;/strong&gt;. The planner treats the parent table as the query target; behind it, rows are routed to child tables (partitions) by a partition key. Same cluster, same Write-Ahead Log (WAL), same &lt;code&gt;shared_buffers&lt;/code&gt;, same connection pool — none of the physical resources are duplicated. What changes is the &lt;em&gt;size&lt;/em&gt; of the things the planner operates on.&lt;/p&gt;
&lt;p&gt;Since Postgres 10, this is &lt;a href=&quot;https://www.postgresql.org/docs/current/ddl-partitioning.html&quot;&gt;&lt;strong&gt;declarative partitioning&lt;/strong&gt;&lt;/a&gt; — a first-class feature. The planner natively understands partition bounds, can prune (skip) partitions that can’t match a query, and can do partition-wise joins and aggregates with the right configuration.&lt;/p&gt;
&lt;p&gt;A quick refresher on the two terms that show up repeatedly throughout this post. &lt;strong&gt;&lt;code&gt;shared_buffers&lt;/code&gt;&lt;/strong&gt; is Postgres’s in-memory cache for table and index pages, sized at startup (typically ~25% of system RAM) and never grows during runtime. Every read first checks &lt;code&gt;shared_buffers&lt;/code&gt;; a miss falls through to the OS page cache and then to disk. &lt;strong&gt;&lt;code&gt;autovacuum&lt;/code&gt;&lt;/strong&gt; is the background process that reclaims space from dead row versions — the leftovers from every &lt;code&gt;UPDATE&lt;/code&gt; and &lt;code&gt;DELETE&lt;/code&gt;, which Postgres can’t free in place because of its MVCC (Multi-Version Concurrency Control) model. When autovacuum can’t keep up, tables &lt;em&gt;bloat&lt;/em&gt; (grow on disk faster than their live row count would suggest) and query plans degrade.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;2-the-three-partitioning-strategies&quot;&gt;2. The Three Partitioning Strategies&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;RANGE&lt;/strong&gt; — each partition owns a contiguous range of values. The textbook case is time-series.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; TABLE&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; events&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    id          &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;bigserial&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    user_id     &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;bigint&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;      NOT NULL&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    payload     jsonb,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    created_at  &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;timestamptz&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; NOT NULL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;PARTITION&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; BY&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; RANGE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (created_at);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; TABLE&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; events_2026_01&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; PARTITION&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; OF events&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    FOR&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; VALUES&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;2026-01-01&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;TO&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;2026-02-01&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; TABLE&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; events_2026_02&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; PARTITION&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; OF events&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    FOR&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; VALUES&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;2026-02-01&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;TO&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;2026-03-01&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;LIST&lt;/strong&gt; — each partition owns an explicit set of discrete values. Useful for low-cardinality categorical dimensions: region, tenant tier, country.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; TABLE&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; customers&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;bigserial&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, region &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, ...)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    PARTITION&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; BY&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; LIST (region);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; TABLE&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; customers_us&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;   PARTITION&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; OF customers &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FOR&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; VALUES&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; IN&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;us-east&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;us-west&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; TABLE&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; customers_eu&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;   PARTITION&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; OF customers &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FOR&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; VALUES&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; IN&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;eu-west&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;eu-central&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; TABLE&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; customers_apac&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; PARTITION&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; OF customers &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FOR&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; VALUES&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; IN&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;ap-south&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;ap-northeast&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;HASH&lt;/strong&gt; — Postgres hashes the key and assigns rows by &lt;code&gt;hash(key) % N&lt;/code&gt;. Used when the goal is even distribution, not range pruning. Equality lookups on the key still prune to one partition (the planner computes the hash); queries without the key fan out to all partitions.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; TABLE&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; messages&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;bigserial&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, channel_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;bigint&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, body &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, ...)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    PARTITION&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; BY&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; HASH&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (channel_id);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; TABLE&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; messages_p0&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; PARTITION&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; OF messages &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FOR&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; VALUES&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; WITH&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (modulus &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;8&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, remainder &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- ... through p7&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also nest these — RANGE-by-time at the outer level with HASH-by-tenant within each month, for example. This is &lt;strong&gt;sub-partitioning&lt;/strong&gt;, and it’s powerful but easy to overuse (more on that in the pitfalls section).&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;3-partition-pruning--the-mechanism-that-makes-it-worth-anything&quot;&gt;3. Partition Pruning — The Mechanism That Makes It Worth Anything&lt;/h2&gt;
&lt;p&gt;All three strategies do the same physical thing: split one logical table into smaller child tables. But splitting alone doesn’t make a single query faster — if Postgres scans every child table looking for matching rows, you’ve turned one big scan into many smaller scans and gained nothing. The strategies pay off only when the planner can &lt;em&gt;skip&lt;/em&gt; the partitions that can’t contain matching rows for a given query. That skipping is called &lt;strong&gt;partition pruning&lt;/strong&gt;, and it’s the connection between “I defined some partitions” and “my queries got faster.”&lt;/p&gt;
&lt;p&gt;With twelve monthly partitions, a one-month query touches one partition, not all twelve. Pruning happens in two phases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Plan-time pruning&lt;/strong&gt; inspects literal &lt;code&gt;WHERE&lt;/code&gt; predicates and rules out partitions whose bounds can’t satisfy them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Execution-time pruning&lt;/strong&gt; kicks in when the partition key arrives at runtime — from a &lt;code&gt;JOIN&lt;/code&gt;, a parameterized statement, or a subquery. Look for &lt;code&gt;Subplans Removed: N&lt;/code&gt; in &lt;code&gt;EXPLAIN ANALYZE&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pruning is fragile in exactly one way: it requires the column to appear plainly in the predicate. Wrapping it in a function defeats it.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- ❌ no pruning — function on partition column blocks it&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; date_trunc(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;month&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, created_at) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;2026-02-01&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- ✅ pruning works&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;2026-02-01&apos;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;2026-03-01&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The single most common partitioning bug: writing the query in the form that defeats pruning and not noticing because the result is still correct, just slow.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;4-local-indexes--and-the-absence-of-global-indexes&quot;&gt;4. Local Indexes — and the Absence of Global Indexes&lt;/h2&gt;
&lt;p&gt;The single most Postgres-specific detail in the partitioning story, and it routinely surprises people coming from Oracle or SQL Server: &lt;strong&gt;Postgres has no global indexes.&lt;/strong&gt; Every index on a partitioned table is implicitly &lt;em&gt;local&lt;/em&gt; — it exists per-partition. &lt;code&gt;CREATE INDEX ON events (user_id)&lt;/code&gt; creates that index on every partition individually, and the parent holds metadata tying them together as one “partitioned index.”&lt;/p&gt;
&lt;p&gt;Consequences:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;UNIQUE&lt;/code&gt; constraints can only be enforced if the partition key is part of the uniqueness columns. A globally unique &lt;code&gt;email&lt;/code&gt; on a hash-partitioned &lt;code&gt;users&lt;/code&gt; table isn’t possible without &lt;code&gt;(email, partition_key)&lt;/code&gt; — usually not what you want.&lt;/li&gt;
&lt;li&gt;Primary keys are enforced per-partition. A &lt;code&gt;bigserial&lt;/code&gt; &lt;code&gt;id&lt;/code&gt; won’t collide because the sequence is global, but the &lt;em&gt;uniqueness check&lt;/em&gt; is local.&lt;/li&gt;
&lt;li&gt;Queries without the partition key in the predicate still use per-partition indexes — but the planner scans them all in turn.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Workarounds exist (managed-uniqueness extensions, externally-issued IDs), but the right move is usually to design the schema so global uniqueness isn’t needed, or so the partition key is implicitly the prefix of the unique key.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;5-the-real-advantages-with-concrete-examples&quot;&gt;5. The Real Advantages (with concrete examples)&lt;/h2&gt;
&lt;p&gt;This is where partitioning earns its place. The standard one-line summary — &lt;em&gt;“it makes large tables manageable”&lt;/em&gt; — undersells it. Here’s what you actually get.&lt;/p&gt;
&lt;h3 id=&quot;51-the-active-working-set-fits-in-shared_buffers&quot;&gt;5.1 The active working set fits in &lt;code&gt;shared_buffers&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Postgres caches heap and index pages in &lt;code&gt;shared_buffers&lt;/code&gt;. If the hot data plus its indexes are larger than the buffer pool, every random lookup is a cache miss and a disk read. Disk reads are roughly 1000× slower than buffer hits.&lt;/p&gt;
&lt;p&gt;Concrete example. A 4 TB unpartitioned &lt;code&gt;events&lt;/code&gt; table with a 600 GB primary-key B-tree on a 128 GB box. The B-tree alone is 5× the buffer pool, so every &lt;code&gt;WHERE id = X&lt;/code&gt; query that doesn’t hit a recently-touched page is a cold disk read. Tail latency is dominated by these misses.&lt;/p&gt;
&lt;p&gt;Partition the same table into 48 monthly partitions. A query filtering by &lt;code&gt;created_at &gt;= &apos;2026-04-01&apos;&lt;/code&gt; now touches a single ~12 GB partition with a ~12 GB B-tree. The active partition fits in the buffer pool comfortably. The query plan is identical — same scan, same join, same filter — but every page read is now a buffer hit instead of a disk miss. Latency drops by an order of magnitude.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Partitioning’s quiet superpower: it doesn’t make the data smaller, it makes the active working set smaller.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;52-retention-becomes-o1&quot;&gt;5.2 Retention becomes O(1)&lt;/h3&gt;
&lt;p&gt;Dropping a partition is a metadata operation. &lt;code&gt;DROP TABLE events_2026_01&lt;/code&gt; on a 200 GB partition takes milliseconds and immediately returns the storage to the OS.&lt;/p&gt;
&lt;p&gt;Compare with the equivalent on an unpartitioned table: &lt;code&gt;DELETE FROM events WHERE created_at &amp;#x3C; &apos;2026-02-01&apos;&lt;/code&gt; is a multi-hour scan that rewrites every page touched (Postgres marks deleted rows as dead tuples instead of removing them in place — the consequence of MVCC). After the DELETE finishes, you need autovacuum to reclaim those dead tuples, &lt;em&gt;another&lt;/em&gt; multi-hour operation. And even after vacuum, the table’s physical size doesn’t shrink, because Postgres can’t return free space mid-file to the OS without &lt;code&gt;VACUUM FULL&lt;/code&gt;, which takes an exclusive lock and blocks reads.&lt;/p&gt;
&lt;p&gt;The retention story is the single biggest practical win of partitioning. Append-heavy tables — events, audit logs, activity streams, metrics — all have a natural retention horizon. Partition by time, drop old partitions on a cron, and the table never actually grows unboundedly.&lt;/p&gt;
&lt;h3 id=&quot;53-operational-isolation-for-ddl&quot;&gt;5.3 Operational isolation for DDL&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ALTER TABLE&lt;/code&gt; on a 4 TB unpartitioned table takes a heavy lock and blocks every other operation on that table. On 48 partitions, you can apply the same schema change one partition at a time, pace the rollout over hours or nights, and the live partitions keep serving queries.&lt;/p&gt;
&lt;p&gt;Concrete example. Adding a column with a non-null default to an unpartitioned 4 TB table rewrites every row — hours of downtime. On 48 partitions, you can do it partition by partition over a few off-hours windows. New writes go to the partitions that already have the column; the migration completes lazily without ever blocking traffic for more than a few seconds per partition.&lt;/p&gt;
&lt;h3 id=&quot;54-autovacuum-parallelism&quot;&gt;5.4 Autovacuum parallelism&lt;/h3&gt;
&lt;p&gt;Autovacuum runs a configurable number of workers (&lt;code&gt;autovacuum_max_workers&lt;/code&gt;, default 3). Each worker handles one relation at a time. On one giant unpartitioned table, three workers can only contend for the same table — there’s nothing for the other two to do. On 48 partitions, three workers can be vacuuming three partitions concurrently. The total throughput of vacuum work is now bounded by your &lt;code&gt;autovacuum_max_workers&lt;/code&gt; and per-worker cost limits, not by the size of one table.&lt;/p&gt;
&lt;p&gt;Partitioning is the cheapest way to give autovacuum useful parallelism on a write-heavy workload.&lt;/p&gt;
&lt;h3 id=&quot;55-per-partition-statistics-better-query-plans&quot;&gt;5.5 Per-partition statistics, better query plans&lt;/h3&gt;
&lt;p&gt;Postgres maintains statistics per table — row counts, value distributions, distinct counts, most-common-values lists — that the planner uses to estimate query costs. On one giant table, these statistics are averages across the entire dataset. On a partitioned table, each partition has its own statistics tuned to that partition’s actual data.&lt;/p&gt;
&lt;p&gt;Example. The &lt;code&gt;events&lt;/code&gt; table has old, stable partitions (Jan–Feb) and a current churning partition (live data). The query distributions are very different — the live partition has more recent timestamps clustered tightly, while older partitions are evenly distributed. Per-partition stats let the planner pick a different (better) plan for each range. On one giant table, the stats are blurred together and the planner makes one mediocre estimate for everything.&lt;/p&gt;
&lt;h3 id=&quot;56-index-only-scans-for-old-data&quot;&gt;5.6 Index-only scans for old data&lt;/h3&gt;
&lt;p&gt;Every heap page has a corresponding bit in Postgres’s &lt;strong&gt;visibility map&lt;/strong&gt; — a compact structure that tracks whether all rows on the page are visible to every active transaction. When an index scan touches a page marked all-visible, Postgres can skip the heap fetch entirely and return data directly from the index entries. This is an &lt;strong&gt;index-only scan&lt;/strong&gt; — the fastest possible read path.&lt;/p&gt;
&lt;p&gt;For a page to be marked all-visible, it must have had no recent modifications &lt;em&gt;and&lt;/em&gt; autovacuum must have run since. On a churning unpartitioned table, most pages are never marked all-visible for long because writes keep touching them. On a partitioned table, old read-mostly partitions stabilize at all-visible permanently. Queries against historical data become index-only scans automatically — &lt;code&gt;Heap Fetches: 0&lt;/code&gt; in EXPLAIN ANALYZE, which is the fastest read path Postgres has.&lt;/p&gt;
&lt;h3 id=&quot;57-tiered-storage-via-tablespaces&quot;&gt;5.7 Tiered storage via tablespaces&lt;/h3&gt;
&lt;p&gt;Postgres lets you create &lt;strong&gt;tablespaces&lt;/strong&gt; — named locations on disk — and assign tables to them. Partitions can live in different tablespaces:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; TABLESPACE&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; cold_storage&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; LOCATION&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;/mnt/slow_ssd&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ALTER&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; TABLE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; events_2024_01 &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; TABLESPACE cold_storage;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ALTER&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; TABLE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; events_2024_02 &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; TABLESPACE cold_storage;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Old, rarely-accessed partitions move to slower (cheaper) storage — slower SSD, spinning rust, even network-attached storage. Hot partitions stay on fast local NVMe. The table is still one logical thing; queries against current data are fast, queries against historical data are slower but possible.&lt;/p&gt;
&lt;p&gt;This is the same pattern that data warehouses use natively. Partitioning gives it to you in operational Postgres without leaving the database.&lt;/p&gt;
&lt;h3 id=&quot;58-create-index-concurrently-scales-linearly&quot;&gt;5.8 &lt;code&gt;CREATE INDEX CONCURRENTLY&lt;/code&gt; scales linearly&lt;/h3&gt;
&lt;p&gt;Building an index on a large table normally takes an exclusive lock. &lt;code&gt;CREATE INDEX CONCURRENTLY&lt;/code&gt; avoids that but does two passes over the table and is several times slower than the locking variant. On a 4 TB unpartitioned table, a concurrent build can take a day.&lt;/p&gt;
&lt;p&gt;On 48 partitions, you can build the index on each partition independently, in parallel if you want, and each build is a fraction of the size. The total wall-clock time can be hours instead of days — and if a build fails on one partition, you’ve only lost one partition’s worth of work, not the entire index.&lt;/p&gt;
&lt;h3 id=&quot;59-capacity-planning-is-visible&quot;&gt;5.9 Capacity planning is visible&lt;/h3&gt;
&lt;p&gt;A single 4 TB table that’s growing… how fast? You can plot the size over time, but the past-versus-current rate is mushed together.&lt;/p&gt;
&lt;p&gt;With monthly partitions, each partition’s size is a clear data point. &lt;code&gt;events_2026_01&lt;/code&gt; is 180 GB; &lt;code&gt;events_2026_02&lt;/code&gt; is 230 GB; &lt;code&gt;events_2026_03&lt;/code&gt; is 290 GB. Now you have a growth curve, per period, that’s trivial to query (&lt;code&gt;SELECT pg_relation_size(&apos;events_2026_03&apos;)&lt;/code&gt;). Capacity planning is a SQL query away.&lt;/p&gt;
&lt;h3 id=&quot;510-selective-backups-and-archival&quot;&gt;5.10 Selective backups and archival&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;pg_dump&lt;/code&gt; on a partitioned table can target specific partitions: &lt;code&gt;pg_dump -t events_2024_*&lt;/code&gt; dumps only old partitions, perhaps for archival to S3 as Parquet files. You don’t need to dump the whole table to back up the inactive parts.&lt;/p&gt;
&lt;p&gt;Many teams build a pipeline: monthly cron job archives the about-to-be-dropped partition to S3 as Parquet, dumps a SQL backup as a sanity copy, then drops the partition. Storage costs go down by an order of magnitude; reads against archived data are still possible (just slower, via S3 Select or a query engine like DuckDB or Athena).&lt;/p&gt;
&lt;h3 id=&quot;511-lock-contention-is-localized&quot;&gt;5.11 Lock contention is localized&lt;/h3&gt;
&lt;p&gt;A long-running &lt;code&gt;VACUUM FULL&lt;/code&gt; or &lt;code&gt;REINDEX&lt;/code&gt; on one partition does not block queries on the other partitions. A locking schema change on &lt;code&gt;events_2024_01&lt;/code&gt; doesn’t stop the application from inserting into &lt;code&gt;events_2026_05&lt;/code&gt;. Operational events that used to take down “the events table” now take down “one slice of the events table” — much smaller blast radius.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;6-internals-what-postgres-does-differently-with-partitioned-tables&quot;&gt;6. Internals: What Postgres Does Differently With Partitioned Tables&lt;/h2&gt;
&lt;p&gt;Behind these advantages are real changes to how Postgres processes queries.&lt;/p&gt;
&lt;h3 id=&quot;query-planner-cost&quot;&gt;Query planner cost&lt;/h3&gt;
&lt;p&gt;Planning time grows with the number of partitions. With 12 partitions and good pruning, planning overhead is negligible. With 5,000 partitions and a query that can’t prune, the planner can spend more time &lt;em&gt;deciding&lt;/em&gt; than the executor spends &lt;em&gt;running&lt;/em&gt;. Postgres 12+ improved per-partition planning cost dramatically (from milliseconds to microseconds), but the rule still holds: &lt;strong&gt;prefer hundreds of partitions over thousands&lt;/strong&gt;. The sweet spot is usually 30–500 partitions per table.&lt;/p&gt;
&lt;h3 id=&quot;partition-wise-joins-and-aggregates&quot;&gt;Partition-wise joins and aggregates&lt;/h3&gt;
&lt;p&gt;Set &lt;code&gt;enable_partitionwise_join = on&lt;/code&gt; and &lt;code&gt;enable_partitionwise_aggregate = on&lt;/code&gt; (both off by default because they increase planning time) and the planner can join matching partitions of two co-partitioned tables in parallel, and aggregate per-partition before combining. For analytical workloads on partitioned fact tables, this can be the difference between a 30-second query and a 2-second one.&lt;/p&gt;
&lt;h3 id=&quot;mvcc-dead-tuples-and-xid-wraparound&quot;&gt;MVCC, dead tuples, and &lt;code&gt;xid&lt;/code&gt; wraparound&lt;/h3&gt;
&lt;p&gt;MVCC keeps multiple versions of each row visible to different transactions. Every &lt;code&gt;UPDATE&lt;/code&gt; writes a new tuple; the old becomes dead, waiting for vacuum. On a 4 TB unpartitioned table with high churn, the dead-tuple bookkeeping is one giant problem; on 48 partitions it’s 48 smaller problems autovacuum workers handle in parallel.&lt;/p&gt;
&lt;p&gt;Postgres’s transaction IDs are 32-bit, and &lt;code&gt;VACUUM FREEZE&lt;/code&gt; exists to mark old tuples visible to all future transactions so their &lt;code&gt;xid&lt;/code&gt;s can be safely reused. On a giant unpartitioned table, freezing is a recurring multi-hour I/O storm. On partitions, freezing is incremental — old read-mostly partitions get frozen once and then never need it again.&lt;/p&gt;
&lt;h3 id=&quot;what-partitioning-shares-and-doesnt-multiply&quot;&gt;What partitioning shares (and doesn’t multiply)&lt;/h3&gt;
&lt;p&gt;It’s worth being explicit about what partitioning does &lt;em&gt;not&lt;/em&gt; duplicate, because that’s what determines whether you need to go further:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;One WAL.&lt;/strong&gt; Every insert across every partition writes to the same Write-Ahead Log. Partitioning doesn’t add write throughput beyond what one machine’s WAL can sustain.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;One &lt;code&gt;shared_buffers&lt;/code&gt;.&lt;/strong&gt; All partitions compete for the same buffer pool.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;One &lt;code&gt;max_connections&lt;/code&gt;.&lt;/strong&gt; Same connection pool, same pgbouncer, same backend processes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;One replication stream.&lt;/strong&gt; Logical or physical, the WAL is one stream that one replica replays.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;One CPU pool.&lt;/strong&gt; Partition-wise parallelism helps, but you’re still bounded by the machine’s cores.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hit any of these ceilings and you’ve left the world of partitioning. That’s the next post in the Distributed Systems series.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;7-pitfalls-and-things-to-watch-for&quot;&gt;7. Pitfalls and Things to Watch For&lt;/h2&gt;
&lt;p&gt;The advantages above are real, but they assume you set things up correctly. Here’s the failure-mode catalogue.&lt;/p&gt;
&lt;h3 id=&quot;71-wrong-partition-key&quot;&gt;7.1 Wrong partition key&lt;/h3&gt;
&lt;p&gt;You hash-partitioned &lt;code&gt;messages&lt;/code&gt; by &lt;code&gt;id&lt;/code&gt;, but every query filters by &lt;code&gt;channel_id&lt;/code&gt;. Every query now touches every partition (no pruning is possible without the key in the predicate), planning time is several times slower than the unpartitioned baseline, and you’ve made things worse.&lt;/p&gt;
&lt;p&gt;The fix is a full re-partition — a migration on the same scale as a shard rebalance: double-write to the new partitioning scheme, backfill, verify, cut over. Pick the key like it’s permanent, because in practice it is.&lt;/p&gt;
&lt;p&gt;A useful rule: &lt;strong&gt;look at the top 20 queries against the table. The column that appears in 90%+ of &lt;code&gt;WHERE&lt;/code&gt; clauses is your partition key candidate. If no single column dominates, partitioning by any of them is going to hurt the queries that filter on the others.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;72-partition-explosion&quot;&gt;7.2 Partition explosion&lt;/h3&gt;
&lt;p&gt;The daily-partition cron got stuck after a server move; 90 days of rows are stacked in &lt;code&gt;events_default&lt;/code&gt; (the catchall partition for rows that don’t match any defined partition). The planner now has to consider hundreds of partition bounds for every query, and the catchall partition has no useful indexes for the workload.&lt;/p&gt;
&lt;p&gt;Worse: someone set up sub-partitioning by tenant inside RANGE-by-time, without bounding the tenant count. You now have 200,000 partitions, query planning takes 30 seconds, and autovacuum is permanently rotating through them.&lt;/p&gt;
&lt;p&gt;Watch the partition count actively. A monitoring alert at “more than 1,000 partitions on any single relation” catches this class of bug before it becomes an outage.&lt;/p&gt;
&lt;h3 id=&quot;73-the-default-partition-is-a-trap&quot;&gt;7.3 The default partition is a trap&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; TABLE&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; events_default&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; PARTITION&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; OF events &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;DEFAULT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The default partition catches rows that don’t match any explicitly-bounded partition. It seems like a safety net, but in practice:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It hides bugs. Your cron didn’t create April’s partition? Rows accumulate in &lt;code&gt;events_default&lt;/code&gt; instead of failing loudly. You notice when queries get slow weeks later.&lt;/li&gt;
&lt;li&gt;It defeats pruning for &lt;em&gt;every&lt;/em&gt; query. As long as &lt;code&gt;events_default&lt;/code&gt; exists, the planner can’t be certain a query doesn’t need to scan it, so it scans it for every query.&lt;/li&gt;
&lt;li&gt;Removing it later requires moving the rows out — and you can’t add a new bounded partition that overlaps with rows already in the default.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The pattern most teams converge on: &lt;strong&gt;don’t create a default partition.&lt;/strong&gt; Let inserts fail when partitions are missing. The failure is loud, immediate, and trivially fixable; the alternative is silent rot.&lt;/p&gt;
&lt;h3 id=&quot;74-sub-partitioning-is-rarely-worth-it&quot;&gt;7.4 Sub-partitioning is rarely worth it&lt;/h3&gt;
&lt;p&gt;The temptation: range-partition by month, then hash-partition each month by tenant. Two levels of pruning, smaller chunks. In practice:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The partition count multiplies (12 months × 32 tenants = 384 partitions).&lt;/li&gt;
&lt;li&gt;Operational complexity multiplies (creating new top-level partitions now creates 32 sub-partitions).&lt;/li&gt;
&lt;li&gt;The pruning benefit is marginal unless both keys are routinely in the query predicate.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If a single level of partitioning has gotten you to chunks of reasonable size (1–50 GB per partition), don’t sub-partition. The exception is genuinely two-dimensional workloads — usually time + tenant — where queries always filter by both.&lt;/p&gt;
&lt;h3 id=&quot;75-attach-and-detach-partition-locks&quot;&gt;7.5 &lt;code&gt;ATTACH&lt;/code&gt; and &lt;code&gt;DETACH&lt;/code&gt; partition locks&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ATTACH PARTITION&lt;/code&gt; briefly takes an &lt;code&gt;ACCESS EXCLUSIVE&lt;/code&gt; lock on the parent table — usually fast but it blocks every read in the meantime. &lt;code&gt;DETACH PARTITION&lt;/code&gt; historically did the same; Postgres 14+ added &lt;code&gt;DETACH PARTITION ... CONCURRENTLY&lt;/code&gt; which avoids the heavy lock but takes longer (two phases, validation step in between).&lt;/p&gt;
&lt;p&gt;If you’re on PG 14+, always use &lt;code&gt;CONCURRENTLY&lt;/code&gt; for detaches. If you’re on an older version, schedule attach/detach operations during low-traffic windows.&lt;/p&gt;
&lt;h3 id=&quot;76-foreign-keys-to-a-partitioned-table&quot;&gt;7.6 Foreign keys &lt;em&gt;to&lt;/em&gt; a partitioned table&lt;/h3&gt;
&lt;p&gt;Foreign keys &lt;em&gt;on&lt;/em&gt; a partitioned table (the partitioned table has the FK) work fine. Foreign keys &lt;em&gt;to&lt;/em&gt; a partitioned table (something else FKs into it) were only added in Postgres 12, and even then have some restrictions — for example, the referenced columns must include the partition key.&lt;/p&gt;
&lt;p&gt;If you’re targeting cross-version compatibility or you’re on PG 11 or earlier, design around this. A common pattern: store the FK reference but don’t declare it; enforce in application code.&lt;/p&gt;
&lt;h3 id=&quot;77-hash-partitioning-hides-scatter-gather&quot;&gt;7.7 Hash partitioning hides scatter-gather&lt;/h3&gt;
&lt;p&gt;Queries that supply the hash partition key prune to one partition. Queries that don’t supply the key — analytics, joins on a different column, full scans — run on every partition. Eight partitions = eight sequential scans, eight index scans, eight result merges.&lt;/p&gt;
&lt;p&gt;This is fine for occasional queries. It’s catastrophic if it’s most of your workload. Always check &lt;code&gt;EXPLAIN ANALYZE&lt;/code&gt; for &lt;code&gt;Append (Subplans Removed: N)&lt;/code&gt; — if &lt;code&gt;N = 0&lt;/code&gt; regularly, you’re hash-partitioning data without using the key, and the partitioning is hurting you.&lt;/p&gt;
&lt;h3 id=&quot;78-function-on-column-defeats-pruning&quot;&gt;7.8 Function-on-column defeats pruning&lt;/h3&gt;
&lt;p&gt;The single most common partitioning bug. The partition key column has to appear plainly in the &lt;code&gt;WHERE&lt;/code&gt; clause for the planner to use the partition bounds.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- ❌ no pruning, scans every partition&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; date_trunc(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;month&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, created_at) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;2026-02-01&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; created_at::&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;2026-02-15&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- ✅ pruning works&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;2026-02-01&apos;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;2026-03-01&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;2026-02-15&apos;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;2026-02-16&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Build a habit of writing predicates against the raw column, and use &lt;code&gt;EXPLAIN ANALYZE&lt;/code&gt; to verify partitions are being skipped on any new query against a partitioned table.&lt;/p&gt;
&lt;h3 id=&quot;79-execution-time-pruning-is-fragile&quot;&gt;7.9 Execution-time pruning is fragile&lt;/h3&gt;
&lt;p&gt;Plan-time pruning handles literal predicates. Execution-time pruning handles values that arrive at runtime (a parameterized query, a &lt;code&gt;JOIN&lt;/code&gt; key, a subquery result). It works — sometimes. Some query shapes never trigger runtime pruning even when the values are clearly available. The query then scans every partition with the per-partition index, which is &lt;em&gt;less&lt;/em&gt; efficient than the unpartitioned baseline.&lt;/p&gt;
&lt;p&gt;Look for &lt;code&gt;Subplans Removed: N&lt;/code&gt; in &lt;code&gt;EXPLAIN ANALYZE&lt;/code&gt;. If &lt;code&gt;N = 0&lt;/code&gt; for a query where the partition key is determined at runtime, you’ve hit a planner limitation. Workarounds include rewriting as a CTE that fixes the value first, or splitting into two queries.&lt;/p&gt;
&lt;h3 id=&quot;710-sequences-and-uniqueness&quot;&gt;7.10 Sequences and uniqueness&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;bigserial&lt;/code&gt; columns work fine across partitions — the sequence is global to the cluster, so IDs don’t collide. But: the uniqueness check is local to each partition. If you somehow inserted a row with &lt;code&gt;id = 42&lt;/code&gt; on &lt;code&gt;events_2026_01&lt;/code&gt; and &lt;code&gt;id = 42&lt;/code&gt; on &lt;code&gt;events_2026_02&lt;/code&gt;, Postgres would not catch it, because the unique index that enforces the PK only exists per-partition.&lt;/p&gt;
&lt;p&gt;In practice this is fine — &lt;code&gt;bigserial&lt;/code&gt; never reuses values — but it’s worth knowing. If you have any path that allows specifying the &lt;code&gt;id&lt;/code&gt; directly (a backfill, a restore, an &lt;code&gt;INSERT ... SELECT&lt;/code&gt;), you can produce duplicate IDs across partitions and not get an error.&lt;/p&gt;
&lt;h3 id=&quot;711-statistics-arent-always-up-to-date&quot;&gt;7.11 Statistics aren’t always up to date&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ANALYZE&lt;/code&gt; collects statistics. On a partitioned table, you can analyze the parent (which combines stats from all partitions) or the individual partitions. The default &lt;code&gt;autovacuum_analyze_*&lt;/code&gt; thresholds are evaluated per-partition, which is good — but the &lt;em&gt;parent&lt;/em&gt; table’s stats only update when you analyze it explicitly.&lt;/p&gt;
&lt;p&gt;If you run queries that aggregate across partitions, the planner uses parent-level stats. Schedule a periodic &lt;code&gt;ANALYZE events&lt;/code&gt; on the parent — once a day is usually fine.&lt;/p&gt;
&lt;h3 id=&quot;712-forgetting-to-create-future-partitions&quot;&gt;7.12 Forgetting to create future partitions&lt;/h3&gt;
&lt;p&gt;You partition by month. You manually create partitions through December. December rolls around. January arrives. Inserts to January start failing because no partition covers &lt;code&gt;2027-01-01&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Either use &lt;a href=&quot;https://github.com/pgpartman/pg_partman&quot;&gt;&lt;code&gt;pg_partman&lt;/code&gt;&lt;/a&gt; to create partitions automatically on a schedule, or wire up your own cron job that creates the next several months ahead. Set up an alert that fires when the latest partition’s upper bound is less than 30 days in the future.&lt;/p&gt;
&lt;h3 id=&quot;713-explain-output-is-much-larger&quot;&gt;7.13 EXPLAIN output is much larger&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;EXPLAIN ANALYZE&lt;/code&gt; on a partitioned table with 48 partitions and no pruning produces a plan with 48 &lt;code&gt;Seq Scan&lt;/code&gt; or &lt;code&gt;Index Scan&lt;/code&gt; nodes — pages of output to scroll through. This is normal but disorienting at first. Get used to looking for &lt;code&gt;Append (Subplans Removed: N)&lt;/code&gt; at the top and reading the surviving sub-plans.&lt;/p&gt;
&lt;h3 id=&quot;714-version-dependencies&quot;&gt;7.14 Version dependencies&lt;/h3&gt;
&lt;p&gt;Partitioning capabilities have evolved fast. A short table:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PG 10&lt;/strong&gt; — declarative partitioning introduced, RANGE and LIST only.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PG 11&lt;/strong&gt; — HASH partitioning, FK &lt;em&gt;to&lt;/em&gt; partitioned tables, partition-wise joins (off by default).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PG 12&lt;/strong&gt; — partition pruning improvements, FK &lt;em&gt;to&lt;/em&gt; partitioned tables fully supported.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PG 13&lt;/strong&gt; — logical replication for partitioned tables.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PG 14&lt;/strong&gt; — &lt;code&gt;DETACH PARTITION ... CONCURRENTLY&lt;/code&gt;, partition-wise stats improvements.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PG 15&lt;/strong&gt; — &lt;code&gt;MERGE&lt;/code&gt; works on partitioned tables.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you’re on an older version, some of the advantages above don’t apply yet. Check your PG version before promising any specific behaviour.&lt;/p&gt;
&lt;h3 id=&quot;715-pg_dump-dumps-each-partition-separately&quot;&gt;7.15 &lt;code&gt;pg_dump&lt;/code&gt; dumps each partition separately&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;pg_dump&lt;/code&gt; of a partitioned table emits separate &lt;code&gt;CREATE TABLE&lt;/code&gt; and &lt;code&gt;COPY&lt;/code&gt; statements per partition. Restore order matters: parents before children, or use &lt;code&gt;--section=pre-data&lt;/code&gt; and &lt;code&gt;--section=data&lt;/code&gt; separately. Most of the time this Just Works, but it can surprise teams running custom backup/restore scripts.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;8-the-ecosystem&quot;&gt;8. The Ecosystem&lt;/h2&gt;
&lt;p&gt;Two tools come up everywhere in production.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/pgpartman/pg_partman&quot;&gt;&lt;strong&gt;&lt;code&gt;pg_partman&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; — the de-facto partition-management extension. Creates partitions ahead of time, drops old ones, optionally indexes new ones. If you’re range-partitioning by time, you almost certainly want &lt;code&gt;pg_partman&lt;/code&gt;. The alternative is a homegrown cron job that gets the timezone wrong on a Sunday at 3 AM.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.timescale.com/&quot;&gt;&lt;strong&gt;TimescaleDB&lt;/strong&gt;&lt;/a&gt; — a Postgres extension purpose-built for time-series. &lt;em&gt;Hypertables&lt;/em&gt; auto-partition by time (and optionally by space); also gives you continuous aggregates, compression, retention policies, and time-bucket query helpers. For unambiguously time-series workloads (metrics, IoT sensor data, financial ticks), it beats hand-rolled partitioning on ergonomics. For mixed OLTP (transactional workloads like e-commerce or SaaS apps) where time is one dimension among many, plain partitioning + &lt;code&gt;pg_partman&lt;/code&gt; is usually better.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;9-when-partitioning-isnt-enough&quot;&gt;9. When Partitioning Isn’t Enough&lt;/h2&gt;
&lt;p&gt;Partitioning solves problems about &lt;em&gt;size per relation&lt;/em&gt;. The dataset is bigger than any single relation can comfortably hold; partitioning splits it into chunks that the planner, the buffer pool, autovacuum, and operational tooling can all handle.&lt;/p&gt;
&lt;p&gt;It does &lt;em&gt;not&lt;/em&gt; solve problems about &lt;em&gt;per-cluster physical resources&lt;/em&gt;. When you’ve maxed out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One machine’s CPU cores&lt;/li&gt;
&lt;li&gt;One machine’s RAM&lt;/li&gt;
&lt;li&gt;One disk’s IOPS&lt;/li&gt;
&lt;li&gt;One WAL’s write throughput&lt;/li&gt;
&lt;li&gt;One replication stream’s apply rate&lt;/li&gt;
&lt;li&gt;One &lt;code&gt;max_connections&lt;/code&gt; ceiling&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;…partitioning won’t help. Every partition still shares those resources. That’s when you start thinking about &lt;em&gt;sharding&lt;/em&gt; — splitting the dataset across multiple Postgres instances. Sharding is a completely different category of operation, with its own architectural questions and its own catalogue of failure modes. It’s covered in the next post in this series’ sibling: &lt;strong&gt;Sharding Postgres&lt;/strong&gt;, the first post in the Distributed Systems series.&lt;/p&gt;
&lt;p&gt;The honest framing: &lt;strong&gt;most teams who think they need sharding actually need partitioning, more RAM, better query plans, or a vertical decomposition of their database&lt;/strong&gt; (splitting &lt;code&gt;billing&lt;/code&gt;, &lt;code&gt;analytics&lt;/code&gt;, &lt;code&gt;notifications&lt;/code&gt; into their own Postgres instances). Real horizontal sharding is for the small number of systems that genuinely outgrow one machine in write throughput or total data size — and even then, often after a year or two of partitioning and vertical decomposition have bought them runway.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;10-the-takeaway&quot;&gt;10. The Takeaway&lt;/h2&gt;
&lt;p&gt;The single highest-leverage operation a Postgres team can perform on a large table is range-partitioning by time, if the workload has any natural retention horizon. The benefits compound: smaller working set, cheaper retention, autovacuum parallelism, index-only scans on old data, operational isolation. The cost — partition creation cron jobs, slightly more complex &lt;code&gt;EXPLAIN&lt;/code&gt; output, a few rules to follow when writing queries — is a small fraction of what you get back.&lt;/p&gt;
&lt;p&gt;The pitfalls above are real, but they’re all knowable up front. Pick the partition key like it’s permanent, don’t create a default partition, watch the partition count, and write your &lt;code&gt;WHERE&lt;/code&gt; clauses without functions on the partition column. Get those right and partitioning is one of the few Postgres features where the upside is huge and the downside is small.&lt;/p&gt;
&lt;p&gt;The architecture that survives is the one you can still understand at 3 AM with a single &lt;code&gt;psql&lt;/code&gt; window open. Partitioning keeps you in that world for much longer than people expect.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;related-reading&quot;&gt;Related reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/db-storage-and-indexing/&quot;&gt;How Databases Actually Store and Find Your Data&lt;/a&gt; — pages, heaps, and TIDs that partitioning splits at the physical level.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/postgres-indexing/&quot;&gt;PostgreSQL Indexing Deep Dive&lt;/a&gt; — local indexes per partition, and how partition pruning interacts with index choice.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/postgres-explain/&quot;&gt;Reading PostgreSQL EXPLAIN Output&lt;/a&gt; — recognising &lt;code&gt;Append&lt;/code&gt;, &lt;code&gt;Subplans Removed&lt;/code&gt;, and partition-wise joins in real plans.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/postgres-sharding/&quot;&gt;Sharding Postgres: When One Database Stops Being Enough&lt;/a&gt; — the next step when partitioning isn’t enough.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/postgres-replication/&quot;&gt;Database Replication: What to Use When&lt;/a&gt; — how partitions interact with WAL streaming and logical replication.&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Sharding Postgres: When One Database Stops Being Enough</title><link>https://abhimanyunagurkar.com/blog/postgres-sharding/</link><guid isPermaLink="true">https://abhimanyunagurkar.com/blog/postgres-sharding/</guid><description>Sharding Postgres at scale — shard keys, routing, distributed transactions, online rebalancing, and the 15 complexities every team eventually hits.</description><pubDate>Wed, 13 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The hot tables are partitioned. The old data is on cheap storage. &lt;code&gt;billing&lt;/code&gt;, &lt;code&gt;analytics&lt;/code&gt;, and &lt;code&gt;notifications&lt;/code&gt; each live on their own Postgres instances now. Read replicas absorb the analytical load. Autovacuum is keeping up. Every single-node tuning lever has been pulled.&lt;/p&gt;
&lt;p&gt;And still — the central tenant data is 12 TB, the write rate exceeds what one disk’s Write-Ahead Log (WAL) can sustain, one machine’s &lt;code&gt;max_connections&lt;/code&gt; ceiling caps how many application servers can talk to the database, and the replica is permanently a few minutes behind during peak traffic. You’ve genuinely outgrown a single Postgres cluster.&lt;/p&gt;
&lt;p&gt;This is when sharding stops being theoretical and starts being the next thing on the roadmap. &lt;strong&gt;Sharding is the horizontal distribution of one dataset across multiple Postgres servers.&lt;/strong&gt; Each shard is a complete Postgres instance, with its own WAL, its own &lt;code&gt;shared_buffers&lt;/code&gt; (Postgres’s in-memory page cache), its own backends, its own backups. They don’t know about each other. A routing layer in the application or in a proxy decides which shard owns which row.&lt;/p&gt;
&lt;p&gt;The honest framing — and the thing every public engineering post about sharding eventually says: &lt;strong&gt;you are trading one big problem (a database that can’t keep up) for a dozen smaller problems (routing, fan-out, hot shards, cross-shard joins, rebalancing, schema migrations, distributed transactions).&lt;/strong&gt; The smaller problems are tractable. They don’t disappear because you picked the right tool.&lt;/p&gt;
&lt;p&gt;This post is the first in the Distributed Systems series. It assumes you’ve already exhausted what one Postgres can do — partitioned the hot tables, decomposed independent domains into their own instances, added read replicas. (If you haven’t, start with the sibling post: &lt;strong&gt;&lt;a href=&quot;/blog/postgres-partitioning/&quot;&gt;Postgres Partitioning&lt;/a&gt;&lt;/strong&gt;.) From here on, we’re talking about the operational regime that begins when one database stops being enough.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;1-the-three-architectural-questions&quot;&gt;1. The Three Architectural Questions&lt;/h2&gt;
&lt;p&gt;Every sharded system answers these. The answers determine everything else.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;What’s the partition key?&lt;/strong&gt; The column you hash or range-distribute on. It separates the &lt;em&gt;single-shard&lt;/em&gt; queries (cheap, scale linearly with shards added) from the &lt;em&gt;scatter-gather&lt;/em&gt; queries (touch every shard, don’t scale). Pick badly and the design fights you for years.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How do clients find the right shard?&lt;/strong&gt; Three approaches, often combined: a directory service (a metadata DB that maps tenants/users to shards), deterministic hashing (compute the shard from the key with no lookup), or a SQL-aware routing proxy.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How do you reshard?&lt;/strong&gt; Eventually a shard gets too hot, a region is added, or the original key was wrong. Online rebalancing is the hardest engineering problem in this space.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&quot;2-shard-keys--the-hardest-decision&quot;&gt;2. Shard Keys — The Hardest Decision&lt;/h2&gt;
&lt;p&gt;For a multi-tenant B2B SaaS, the answer is almost always &lt;code&gt;tenant_id&lt;/code&gt;. Every tenant’s data lives on one shard. Queries already filter by tenant. No single tenant is large enough to need their data spread across machines. This is the architecture Notion, Figma, Slack (on Vitess), and most B2B systems converge on.&lt;/p&gt;
&lt;p&gt;For a B2C product, &lt;code&gt;user_id&lt;/code&gt; works for user-centric reads (profile, feed, messages) but breaks down for global features (timelines of accounts you follow, group chats, marketplace browses). Large B2C systems usually shard by user &lt;em&gt;and&lt;/em&gt; maintain denormalized cross-cutting structures — fanout tables, materialized timelines — that absorb the scatter-gather cost up front.&lt;/p&gt;
&lt;p&gt;For geo-distributed products, &lt;code&gt;region&lt;/code&gt; works as a &lt;em&gt;coarse&lt;/em&gt; shard key (data sovereignty, latency), with finer-grained tenant or user sharding nested inside each region.&lt;/p&gt;
&lt;p&gt;The wrong shard keys are obvious in retrospect:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Timestamps for write-heavy workloads.&lt;/strong&gt; Every write goes to the newest shard. The hot-shard problem in its purest form.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auto-incrementing IDs.&lt;/strong&gt; Same issue when range-sharded; hashing fixes the imbalance but you still scatter-gather for almost everything.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Low-cardinality columns&lt;/strong&gt; (country code, plan tier). Some shards end up 10× the size of others, and you can’t rebalance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A useful rule: &lt;strong&gt;look at your top 20 query predicates. If 90%+ filter by a particular column, that’s your shard key. If no single column dominates, you don’t have a sharding problem — you have a data-model problem.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;3-consistent-hashing-and-the-logicalphysical-split&quot;&gt;3. Consistent Hashing and the Logical/Physical Split&lt;/h2&gt;
&lt;p&gt;A naive &lt;code&gt;hash(key) % N&lt;/code&gt; design hits a wall when &lt;code&gt;N&lt;/code&gt; changes. Suppose today &lt;code&gt;N = 3&lt;/code&gt;, so tenant 42 resolves to &lt;code&gt;hash(42) % 3 = 0&lt;/code&gt; — shard 0. Tomorrow you add a fourth machine: &lt;code&gt;hash(42) % 4 = 2&lt;/code&gt; — shard 2. The same tenant ID now points to a &lt;em&gt;different&lt;/em&gt; shard. Almost every tenant gets a new assignment, and every row in the system has to be physically copied to its new home. That’s called &lt;strong&gt;re-keying&lt;/strong&gt;: the routing function changed, so the answer to “which shard does this row belong to?” changed for nearly everyone.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Consistent hashing&lt;/strong&gt; fixes this by mapping both keys and nodes onto a circular hash space. Each key is owned by the next node clockwise from it. When you add a node, only the keys in the arc between the new node and its clockwise neighbour need to move — the rest stay where they were.&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Consistent hashing: keys map to the next clockwise node on a circular hash ring; adding a new node only moves the keys that fall in its arc&quot;&gt;&lt;svg viewBox=&quot;0 0 900 460&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; style=&quot;max-width: 100%; height: auto;&quot;&gt;&lt;text x=&quot;230&quot; y=&quot;36&quot; text-anchor=&quot;middle&quot; font-family=&quot;system-ui, sans-serif&quot; font-size=&quot;14&quot; font-weight=&quot;600&quot; fill=&quot;#1f2328&quot;&gt;Before: 3 nodes on the hash ring&lt;/text&gt;&lt;circle cx=&quot;230&quot; cy=&quot;230&quot; r=&quot;130&quot; fill=&quot;none&quot; stroke=&quot;#8b949e&quot; stroke-width=&quot;1.5&quot; stroke-dasharray=&quot;4 4&quot;&gt;&lt;/circle&gt;&lt;circle cx=&quot;230&quot; cy=&quot;100&quot; r=&quot;14&quot; fill=&quot;#3fb950&quot;&gt;&lt;/circle&gt;&lt;text x=&quot;230&quot; y=&quot;84&quot; text-anchor=&quot;middle&quot; font-family=&quot;system-ui, sans-serif&quot; font-size=&quot;13&quot; font-weight=&quot;600&quot; fill=&quot;#1f2328&quot;&gt;A&lt;/text&gt;&lt;circle cx=&quot;342.6&quot; cy=&quot;295&quot; r=&quot;14&quot; fill=&quot;#388bfd&quot;&gt;&lt;/circle&gt;&lt;text x=&quot;365&quot; y=&quot;301&quot; text-anchor=&quot;start&quot; font-family=&quot;system-ui, sans-serif&quot; font-size=&quot;13&quot; font-weight=&quot;600&quot; fill=&quot;#1f2328&quot;&gt;B&lt;/text&gt;&lt;circle cx=&quot;117.4&quot; cy=&quot;295&quot; r=&quot;14&quot; fill=&quot;#bc8cff&quot;&gt;&lt;/circle&gt;&lt;text x=&quot;95&quot; y=&quot;301&quot; text-anchor=&quot;end&quot; font-family=&quot;system-ui, sans-serif&quot; font-size=&quot;13&quot; font-weight=&quot;600&quot; fill=&quot;#1f2328&quot;&gt;C&lt;/text&gt;&lt;circle cx=&quot;295&quot; cy=&quot;117.4&quot; r=&quot;7&quot; fill=&quot;#388bfd&quot; stroke=&quot;#1f2328&quot; stroke-width=&quot;1&quot;&gt;&lt;/circle&gt;&lt;circle cx=&quot;321.9&quot; cy=&quot;138.1&quot; r=&quot;7&quot; fill=&quot;#388bfd&quot; stroke=&quot;#1f2328&quot; stroke-width=&quot;1&quot;&gt;&lt;/circle&gt;&lt;circle cx=&quot;360&quot; cy=&quot;230&quot; r=&quot;7&quot; fill=&quot;#388bfd&quot; stroke=&quot;#1f2328&quot; stroke-width=&quot;1&quot;&gt;&lt;/circle&gt;&lt;circle cx=&quot;295&quot; cy=&quot;342.6&quot; r=&quot;7&quot; fill=&quot;#bc8cff&quot; stroke=&quot;#1f2328&quot; stroke-width=&quot;1&quot;&gt;&lt;/circle&gt;&lt;circle cx=&quot;230&quot; cy=&quot;360&quot; r=&quot;7&quot; fill=&quot;#bc8cff&quot; stroke=&quot;#1f2328&quot; stroke-width=&quot;1&quot;&gt;&lt;/circle&gt;&lt;circle cx=&quot;165&quot; cy=&quot;342.6&quot; r=&quot;7&quot; fill=&quot;#bc8cff&quot; stroke=&quot;#1f2328&quot; stroke-width=&quot;1&quot;&gt;&lt;/circle&gt;&lt;circle cx=&quot;100&quot; cy=&quot;230&quot; r=&quot;7&quot; fill=&quot;#3fb950&quot; stroke=&quot;#1f2328&quot; stroke-width=&quot;1&quot;&gt;&lt;/circle&gt;&lt;circle cx=&quot;165&quot; cy=&quot;117.4&quot; r=&quot;7&quot; fill=&quot;#3fb950&quot; stroke=&quot;#1f2328&quot; stroke-width=&quot;1&quot;&gt;&lt;/circle&gt;&lt;text x=&quot;230&quot; y=&quot;410&quot; text-anchor=&quot;middle&quot; font-family=&quot;system-ui, sans-serif&quot; font-size=&quot;12&quot; fill=&quot;#57606a&quot;&gt;Each key is owned by the next clockwise node.&lt;/text&gt;&lt;text x=&quot;230&quot; y=&quot;430&quot; text-anchor=&quot;middle&quot; font-family=&quot;system-ui, sans-serif&quot; font-size=&quot;12&quot; fill=&quot;#57606a&quot;&gt;Key colour matches its owner.&lt;/text&gt;&lt;line x1=&quot;450&quot; y1=&quot;60&quot; x2=&quot;450&quot; y2=&quot;420&quot; stroke=&quot;#d0d7de&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3 3&quot;&gt;&lt;/line&gt;&lt;text x=&quot;670&quot; y=&quot;36&quot; text-anchor=&quot;middle&quot; font-family=&quot;system-ui, sans-serif&quot; font-size=&quot;14&quot; font-weight=&quot;600&quot; fill=&quot;#1f2328&quot;&gt;After: node D added between A and B&lt;/text&gt;&lt;path d=&quot;M 670 100 A 130 130 0 0 1 782.6 165&quot; fill=&quot;none&quot; stroke=&quot;#f0883e&quot; stroke-width=&quot;4&quot; opacity=&quot;0.5&quot;&gt;&lt;/path&gt;&lt;circle cx=&quot;670&quot; cy=&quot;230&quot; r=&quot;130&quot; fill=&quot;none&quot; stroke=&quot;#8b949e&quot; stroke-width=&quot;1.5&quot; stroke-dasharray=&quot;4 4&quot;&gt;&lt;/circle&gt;&lt;circle cx=&quot;670&quot; cy=&quot;100&quot; r=&quot;14&quot; fill=&quot;#3fb950&quot;&gt;&lt;/circle&gt;&lt;text x=&quot;670&quot; y=&quot;84&quot; text-anchor=&quot;middle&quot; font-family=&quot;system-ui, sans-serif&quot; font-size=&quot;13&quot; font-weight=&quot;600&quot; fill=&quot;#1f2328&quot;&gt;A&lt;/text&gt;&lt;circle cx=&quot;782.6&quot; cy=&quot;165&quot; r=&quot;14&quot; fill=&quot;#f0883e&quot;&gt;&lt;/circle&gt;&lt;text x=&quot;805&quot; y=&quot;170&quot; text-anchor=&quot;start&quot; font-family=&quot;system-ui, sans-serif&quot; font-size=&quot;13&quot; font-weight=&quot;600&quot; fill=&quot;#1f2328&quot;&gt;D (new)&lt;/text&gt;&lt;circle cx=&quot;782.6&quot; cy=&quot;295&quot; r=&quot;14&quot; fill=&quot;#388bfd&quot;&gt;&lt;/circle&gt;&lt;text x=&quot;805&quot; y=&quot;301&quot; text-anchor=&quot;start&quot; font-family=&quot;system-ui, sans-serif&quot; font-size=&quot;13&quot; font-weight=&quot;600&quot; fill=&quot;#1f2328&quot;&gt;B&lt;/text&gt;&lt;circle cx=&quot;557.4&quot; cy=&quot;295&quot; r=&quot;14&quot; fill=&quot;#bc8cff&quot;&gt;&lt;/circle&gt;&lt;text x=&quot;535&quot; y=&quot;301&quot; text-anchor=&quot;end&quot; font-family=&quot;system-ui, sans-serif&quot; font-size=&quot;13&quot; font-weight=&quot;600&quot; fill=&quot;#1f2328&quot;&gt;C&lt;/text&gt;&lt;circle cx=&quot;735&quot; cy=&quot;117.4&quot; r=&quot;7&quot; fill=&quot;#f0883e&quot; stroke=&quot;#1f2328&quot; stroke-width=&quot;1&quot;&gt;&lt;/circle&gt;&lt;text x=&quot;735&quot; y=&quot;105&quot; text-anchor=&quot;middle&quot; font-family=&quot;system-ui, sans-serif&quot; font-size=&quot;11&quot; font-weight=&quot;600&quot; fill=&quot;#f0883e&quot;&gt;moved&lt;/text&gt;&lt;circle cx=&quot;761.9&quot; cy=&quot;138.1&quot; r=&quot;7&quot; fill=&quot;#f0883e&quot; stroke=&quot;#1f2328&quot; stroke-width=&quot;1&quot;&gt;&lt;/circle&gt;&lt;circle cx=&quot;800&quot; cy=&quot;230&quot; r=&quot;7&quot; fill=&quot;#388bfd&quot; stroke=&quot;#1f2328&quot; stroke-width=&quot;1&quot;&gt;&lt;/circle&gt;&lt;circle cx=&quot;735&quot; cy=&quot;342.6&quot; r=&quot;7&quot; fill=&quot;#bc8cff&quot; stroke=&quot;#1f2328&quot; stroke-width=&quot;1&quot;&gt;&lt;/circle&gt;&lt;circle cx=&quot;670&quot; cy=&quot;360&quot; r=&quot;7&quot; fill=&quot;#bc8cff&quot; stroke=&quot;#1f2328&quot; stroke-width=&quot;1&quot;&gt;&lt;/circle&gt;&lt;circle cx=&quot;605&quot; cy=&quot;342.6&quot; r=&quot;7&quot; fill=&quot;#bc8cff&quot; stroke=&quot;#1f2328&quot; stroke-width=&quot;1&quot;&gt;&lt;/circle&gt;&lt;circle cx=&quot;540&quot; cy=&quot;230&quot; r=&quot;7&quot; fill=&quot;#3fb950&quot; stroke=&quot;#1f2328&quot; stroke-width=&quot;1&quot;&gt;&lt;/circle&gt;&lt;circle cx=&quot;605&quot; cy=&quot;117.4&quot; r=&quot;7&quot; fill=&quot;#3fb950&quot; stroke=&quot;#1f2328&quot; stroke-width=&quot;1&quot;&gt;&lt;/circle&gt;&lt;text x=&quot;670&quot; y=&quot;410&quot; text-anchor=&quot;middle&quot; font-family=&quot;system-ui, sans-serif&quot; font-size=&quot;12&quot; fill=&quot;#57606a&quot;&gt;Only keys in D&apos;s arc moved (orange).&lt;/text&gt;&lt;text x=&quot;670&quot; y=&quot;430&quot; text-anchor=&quot;middle&quot; font-family=&quot;system-ui, sans-serif&quot; font-size=&quot;12&quot; fill=&quot;#57606a&quot;&gt;The other 6 keys stayed exactly where they were.&lt;/text&gt;&lt;/svg&gt;&lt;/figure&gt;
&lt;p&gt;In a 3-node ring, adding a 4th node moves roughly 1/4 of the keys. With &lt;code&gt;hash(key) % N&lt;/code&gt;, adding a 4th node would have moved almost &lt;em&gt;all&lt;/em&gt; of them. That’s the whole point.&lt;/p&gt;
&lt;p&gt;But most production systems use a simpler trick on top: decouple logical and physical shards.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pick a logical shard count larger than you’ll ever need (256, 1024, 4096).&lt;/li&gt;
&lt;li&gt;Distribute logical shards across a smaller number of physical instances.&lt;/li&gt;
&lt;li&gt;Keep a directory &lt;code&gt;tenant_id → logical_shard → physical_instance&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;When a machine gets hot, move a few logical shards. No re-keying.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Many tenants hash to a fixed set of logical shards; logical shards are distributed across a smaller set of physical Postgres instances; moving a logical shard between instances requires no tenant remapping&quot;&gt;&lt;svg viewBox=&quot;0 0 900 480&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; style=&quot;max-width: 100%; height: auto;&quot;&gt;&lt;text x=&quot;450&quot; y=&quot;32&quot; text-anchor=&quot;middle&quot; font-family=&quot;system-ui, sans-serif&quot; font-size=&quot;14&quot; font-weight=&quot;600&quot; fill=&quot;#1f2328&quot;&gt;Tenants → logical shards → physical instances&lt;/text&gt;&lt;text x=&quot;60&quot; y=&quot;95&quot; text-anchor=&quot;start&quot; font-family=&quot;system-ui, sans-serif&quot; font-size=&quot;12&quot; font-weight=&quot;600&quot; fill=&quot;#57606a&quot;&gt;Tenants&lt;/text&gt;&lt;text x=&quot;60&quot; y=&quot;225&quot; text-anchor=&quot;start&quot; font-family=&quot;system-ui, sans-serif&quot; font-size=&quot;12&quot; font-weight=&quot;600&quot; fill=&quot;#57606a&quot;&gt;Logical shards&lt;/text&gt;&lt;text x=&quot;60&quot; y=&quot;395&quot; text-anchor=&quot;start&quot; font-family=&quot;system-ui, sans-serif&quot; font-size=&quot;12&quot; font-weight=&quot;600&quot; fill=&quot;#57606a&quot;&gt;Physical instances&lt;/text&gt;&lt;circle cx=&quot;200&quot; cy=&quot;90&quot; r=&quot;8&quot; fill=&quot;#6e7681&quot;&gt;&lt;/circle&gt;&lt;text x=&quot;200&quot; y=&quot;73&quot; text-anchor=&quot;middle&quot; font-family=&quot;ui-monospace, Menlo, monospace&quot; font-size=&quot;10&quot; fill=&quot;#1f2328&quot;&gt;t1&lt;/text&gt;&lt;circle cx=&quot;260&quot; cy=&quot;90&quot; r=&quot;8&quot; fill=&quot;#6e7681&quot;&gt;&lt;/circle&gt;&lt;text x=&quot;260&quot; y=&quot;73&quot; text-anchor=&quot;middle&quot; font-family=&quot;ui-monospace, Menlo, monospace&quot; font-size=&quot;10&quot; fill=&quot;#1f2328&quot;&gt;t2&lt;/text&gt;&lt;circle cx=&quot;335&quot; cy=&quot;90&quot; r=&quot;8&quot; fill=&quot;#6e7681&quot;&gt;&lt;/circle&gt;&lt;text x=&quot;335&quot; y=&quot;73&quot; text-anchor=&quot;middle&quot; font-family=&quot;ui-monospace, Menlo, monospace&quot; font-size=&quot;10&quot; fill=&quot;#1f2328&quot;&gt;t3&lt;/text&gt;&lt;circle cx=&quot;395&quot; cy=&quot;90&quot; r=&quot;8&quot; fill=&quot;#6e7681&quot;&gt;&lt;/circle&gt;&lt;text x=&quot;395&quot; y=&quot;73&quot; text-anchor=&quot;middle&quot; font-family=&quot;ui-monospace, Menlo, monospace&quot; font-size=&quot;10&quot; fill=&quot;#1f2328&quot;&gt;t4&lt;/text&gt;&lt;circle cx=&quot;475&quot; cy=&quot;90&quot; r=&quot;8&quot; fill=&quot;#6e7681&quot;&gt;&lt;/circle&gt;&lt;text x=&quot;475&quot; y=&quot;73&quot; text-anchor=&quot;middle&quot; font-family=&quot;ui-monospace, Menlo, monospace&quot; font-size=&quot;10&quot; fill=&quot;#1f2328&quot;&gt;t5&lt;/text&gt;&lt;circle cx=&quot;535&quot; cy=&quot;90&quot; r=&quot;8&quot; fill=&quot;#6e7681&quot;&gt;&lt;/circle&gt;&lt;text x=&quot;535&quot; y=&quot;73&quot; text-anchor=&quot;middle&quot; font-family=&quot;ui-monospace, Menlo, monospace&quot; font-size=&quot;10&quot; fill=&quot;#1f2328&quot;&gt;t6&lt;/text&gt;&lt;circle cx=&quot;615&quot; cy=&quot;90&quot; r=&quot;8&quot; fill=&quot;#6e7681&quot;&gt;&lt;/circle&gt;&lt;text x=&quot;615&quot; y=&quot;73&quot; text-anchor=&quot;middle&quot; font-family=&quot;ui-monospace, Menlo, monospace&quot; font-size=&quot;10&quot; fill=&quot;#1f2328&quot;&gt;t7&lt;/text&gt;&lt;circle cx=&quot;675&quot; cy=&quot;90&quot; r=&quot;8&quot; fill=&quot;#6e7681&quot;&gt;&lt;/circle&gt;&lt;text x=&quot;675&quot; y=&quot;73&quot; text-anchor=&quot;middle&quot; font-family=&quot;ui-monospace, Menlo, monospace&quot; font-size=&quot;10&quot; fill=&quot;#1f2328&quot;&gt;t8&lt;/text&gt;&lt;circle cx=&quot;755&quot; cy=&quot;90&quot; r=&quot;8&quot; fill=&quot;#6e7681&quot;&gt;&lt;/circle&gt;&lt;text x=&quot;755&quot; y=&quot;73&quot; text-anchor=&quot;middle&quot; font-family=&quot;ui-monospace, Menlo, monospace&quot; font-size=&quot;10&quot; fill=&quot;#1f2328&quot;&gt;t9&lt;/text&gt;&lt;circle cx=&quot;815&quot; cy=&quot;90&quot; r=&quot;8&quot; fill=&quot;#6e7681&quot;&gt;&lt;/circle&gt;&lt;text x=&quot;815&quot; y=&quot;73&quot; text-anchor=&quot;middle&quot; font-family=&quot;ui-monospace, Menlo, monospace&quot; font-size=&quot;10&quot; fill=&quot;#1f2328&quot;&gt;t10&lt;/text&gt;&lt;line x1=&quot;200&quot; y1=&quot;100&quot; x2=&quot;230&quot; y2=&quot;210&quot; stroke=&quot;#8b949e&quot; stroke-width=&quot;1&quot;&gt;&lt;/line&gt;&lt;line x1=&quot;260&quot; y1=&quot;100&quot; x2=&quot;230&quot; y2=&quot;210&quot; stroke=&quot;#8b949e&quot; stroke-width=&quot;1&quot;&gt;&lt;/line&gt;&lt;line x1=&quot;335&quot; y1=&quot;100&quot; x2=&quot;365&quot; y2=&quot;210&quot; stroke=&quot;#8b949e&quot; stroke-width=&quot;1&quot;&gt;&lt;/line&gt;&lt;line x1=&quot;395&quot; y1=&quot;100&quot; x2=&quot;365&quot; y2=&quot;210&quot; stroke=&quot;#8b949e&quot; stroke-width=&quot;1&quot;&gt;&lt;/line&gt;&lt;line x1=&quot;475&quot; y1=&quot;100&quot; x2=&quot;505&quot; y2=&quot;210&quot; stroke=&quot;#8b949e&quot; stroke-width=&quot;1&quot;&gt;&lt;/line&gt;&lt;line x1=&quot;535&quot; y1=&quot;100&quot; x2=&quot;505&quot; y2=&quot;210&quot; stroke=&quot;#8b949e&quot; stroke-width=&quot;1&quot;&gt;&lt;/line&gt;&lt;line x1=&quot;615&quot; y1=&quot;100&quot; x2=&quot;645&quot; y2=&quot;210&quot; stroke=&quot;#8b949e&quot; stroke-width=&quot;1&quot;&gt;&lt;/line&gt;&lt;line x1=&quot;675&quot; y1=&quot;100&quot; x2=&quot;645&quot; y2=&quot;210&quot; stroke=&quot;#8b949e&quot; stroke-width=&quot;1&quot;&gt;&lt;/line&gt;&lt;line x1=&quot;755&quot; y1=&quot;100&quot; x2=&quot;785&quot; y2=&quot;210&quot; stroke=&quot;#8b949e&quot; stroke-width=&quot;1&quot;&gt;&lt;/line&gt;&lt;line x1=&quot;815&quot; y1=&quot;100&quot; x2=&quot;785&quot; y2=&quot;210&quot; stroke=&quot;#8b949e&quot; stroke-width=&quot;1&quot;&gt;&lt;/line&gt;&lt;rect x=&quot;190&quot; y=&quot;210&quot; width=&quot;80&quot; height=&quot;34&quot; rx=&quot;4&quot; fill=&quot;#388bfd&quot; stroke=&quot;#1f2328&quot; stroke-width=&quot;1&quot;&gt;&lt;/rect&gt;&lt;text x=&quot;230&quot; y=&quot;232&quot; text-anchor=&quot;middle&quot; font-family=&quot;ui-monospace, Menlo, monospace&quot; font-size=&quot;12&quot; font-weight=&quot;600&quot; fill=&quot;#ffffff&quot;&gt;LS-0&lt;/text&gt;&lt;rect x=&quot;325&quot; y=&quot;210&quot; width=&quot;80&quot; height=&quot;34&quot; rx=&quot;4&quot; fill=&quot;#388bfd&quot; stroke=&quot;#1f2328&quot; stroke-width=&quot;1&quot;&gt;&lt;/rect&gt;&lt;text x=&quot;365&quot; y=&quot;232&quot; text-anchor=&quot;middle&quot; font-family=&quot;ui-monospace, Menlo, monospace&quot; font-size=&quot;12&quot; font-weight=&quot;600&quot; fill=&quot;#ffffff&quot;&gt;LS-1&lt;/text&gt;&lt;rect x=&quot;465&quot; y=&quot;210&quot; width=&quot;80&quot; height=&quot;34&quot; rx=&quot;4&quot; fill=&quot;#388bfd&quot; stroke=&quot;#1f2328&quot; stroke-width=&quot;1&quot;&gt;&lt;/rect&gt;&lt;text x=&quot;505&quot; y=&quot;232&quot; text-anchor=&quot;middle&quot; font-family=&quot;ui-monospace, Menlo, monospace&quot; font-size=&quot;12&quot; font-weight=&quot;600&quot; fill=&quot;#ffffff&quot;&gt;LS-2&lt;/text&gt;&lt;rect x=&quot;605&quot; y=&quot;210&quot; width=&quot;80&quot; height=&quot;34&quot; rx=&quot;4&quot; fill=&quot;#f0883e&quot; stroke=&quot;#1f2328&quot; stroke-width=&quot;2&quot; stroke-dasharray=&quot;3 3&quot;&gt;&lt;/rect&gt;&lt;text x=&quot;645&quot; y=&quot;232&quot; text-anchor=&quot;middle&quot; font-family=&quot;ui-monospace, Menlo, monospace&quot; font-size=&quot;12&quot; font-weight=&quot;600&quot; fill=&quot;#ffffff&quot;&gt;LS-3&lt;/text&gt;&lt;rect x=&quot;745&quot; y=&quot;210&quot; width=&quot;80&quot; height=&quot;34&quot; rx=&quot;4&quot; fill=&quot;#388bfd&quot; stroke=&quot;#1f2328&quot; stroke-width=&quot;1&quot;&gt;&lt;/rect&gt;&lt;text x=&quot;785&quot; y=&quot;232&quot; text-anchor=&quot;middle&quot; font-family=&quot;ui-monospace, Menlo, monospace&quot; font-size=&quot;12&quot; font-weight=&quot;600&quot; fill=&quot;#ffffff&quot;&gt;LS-4&lt;/text&gt;&lt;line x1=&quot;230&quot; y1=&quot;244&quot; x2=&quot;245&quot; y2=&quot;345&quot; stroke=&quot;#8b949e&quot; stroke-width=&quot;1&quot;&gt;&lt;/line&gt;&lt;line x1=&quot;365&quot; y1=&quot;244&quot; x2=&quot;285&quot; y2=&quot;345&quot; stroke=&quot;#8b949e&quot; stroke-width=&quot;1&quot;&gt;&lt;/line&gt;&lt;line x1=&quot;505&quot; y1=&quot;244&quot; x2=&quot;520&quot; y2=&quot;345&quot; stroke=&quot;#8b949e&quot; stroke-width=&quot;1&quot;&gt;&lt;/line&gt;&lt;line x1=&quot;645&quot; y1=&quot;244&quot; x2=&quot;755&quot; y2=&quot;345&quot; stroke=&quot;#f0883e&quot; stroke-width=&quot;1.5&quot; stroke-dasharray=&quot;4 3&quot;&gt;&lt;/line&gt;&lt;line x1=&quot;785&quot; y1=&quot;244&quot; x2=&quot;795&quot; y2=&quot;345&quot; stroke=&quot;#8b949e&quot; stroke-width=&quot;1&quot;&gt;&lt;/line&gt;&lt;rect x=&quot;120&quot; y=&quot;345&quot; width=&quot;240&quot; height=&quot;70&quot; rx=&quot;6&quot; fill=&quot;#3fb950&quot; stroke=&quot;#1f2328&quot; stroke-width=&quot;1&quot;&gt;&lt;/rect&gt;&lt;text x=&quot;240&quot; y=&quot;375&quot; text-anchor=&quot;middle&quot; font-family=&quot;ui-monospace, Menlo, monospace&quot; font-size=&quot;13&quot; font-weight=&quot;700&quot; fill=&quot;#0a0a0a&quot;&gt;pg-01&lt;/text&gt;&lt;text x=&quot;240&quot; y=&quot;395&quot; text-anchor=&quot;middle&quot; font-family=&quot;system-ui, sans-serif&quot; font-size=&quot;11&quot; fill=&quot;#0a0a0a&quot;&gt;hosts LS-0, LS-1&lt;/text&gt;&lt;rect x=&quot;400&quot; y=&quot;345&quot; width=&quot;240&quot; height=&quot;70&quot; rx=&quot;6&quot; fill=&quot;#3fb950&quot; stroke=&quot;#1f2328&quot; stroke-width=&quot;1&quot;&gt;&lt;/rect&gt;&lt;text x=&quot;520&quot; y=&quot;375&quot; text-anchor=&quot;middle&quot; font-family=&quot;ui-monospace, Menlo, monospace&quot; font-size=&quot;13&quot; font-weight=&quot;700&quot; fill=&quot;#0a0a0a&quot;&gt;pg-02&lt;/text&gt;&lt;text x=&quot;520&quot; y=&quot;395&quot; text-anchor=&quot;middle&quot; font-family=&quot;system-ui, sans-serif&quot; font-size=&quot;11&quot; fill=&quot;#0a0a0a&quot;&gt;hosts LS-2 (was LS-3)&lt;/text&gt;&lt;rect x=&quot;680&quot; y=&quot;345&quot; width=&quot;240&quot; height=&quot;70&quot; rx=&quot;6&quot; fill=&quot;#3fb950&quot; stroke=&quot;#1f2328&quot; stroke-width=&quot;1&quot;&gt;&lt;/rect&gt;&lt;text x=&quot;800&quot; y=&quot;375&quot; text-anchor=&quot;middle&quot; font-family=&quot;ui-monospace, Menlo, monospace&quot; font-size=&quot;13&quot; font-weight=&quot;700&quot; fill=&quot;#0a0a0a&quot;&gt;pg-03&lt;/text&gt;&lt;text x=&quot;800&quot; y=&quot;395&quot; text-anchor=&quot;middle&quot; font-family=&quot;system-ui, sans-serif&quot; font-size=&quot;11&quot; fill=&quot;#0a0a0a&quot;&gt;hosts LS-3 (moved), LS-4&lt;/text&gt;&lt;text x=&quot;450&quot; y=&quot;445&quot; text-anchor=&quot;middle&quot; font-family=&quot;system-ui, sans-serif&quot; font-size=&quot;12&quot; fill=&quot;#57606a&quot;&gt;LS-3 moved from pg-02 to pg-03 — its rows were physically copied across. But t7 &amp;#x26; t8 still hash to LS-3.&lt;/text&gt;&lt;text x=&quot;450&quot; y=&quot;463&quot; text-anchor=&quot;middle&quot; font-family=&quot;system-ui, sans-serif&quot; font-size=&quot;12&quot; fill=&quot;#57606a&quot;&gt;The routing function never changes (no re-keying). Only one logical shard&apos;s data crossed the wire — not the whole cluster.&lt;/text&gt;&lt;/svg&gt;&lt;/figure&gt;
&lt;p&gt;To be precise about what does and doesn’t move: &lt;strong&gt;the data still gets copied.&lt;/strong&gt; When LS-3 migrates from pg-02 to pg-03, every row belonging to LS-3 is physically transferred across — there’s no magic that avoids the bytes-on-disk part. That copy uses the online-rebalancing playbook later in this post (double-write → backfill → verify → cut over), and at real scale it can take hours.&lt;/p&gt;
&lt;p&gt;What the indirection avoids is &lt;strong&gt;re-keying&lt;/strong&gt;. With naive &lt;code&gt;hash(tenant_id) % N&lt;/code&gt;, adding one machine to a 3-node cluster changes &lt;code&gt;N&lt;/code&gt; from 3 to 4, which changes the hash result for roughly 3/4 of all tenants, which means 3/4 of the entire dataset has to move. With the logical/physical split, the routing function (&lt;code&gt;hash(tenant_id) % 256&lt;/code&gt;) is permanent — every tenant always resolves to the same logical shard, forever. To rebalance, you pick one logical shard, update its directory row, and copy &lt;em&gt;that&lt;/em&gt; shard’s data. The difference is “copy 1/256 of the dataset” versus “copy 3/4 of the dataset” — for the same operational outcome of adding one machine.&lt;/p&gt;
&lt;p&gt;This is the architecture published by &lt;a href=&quot;https://www.notion.com/blog/sharding-postgres-at-notion&quot;&gt;Notion&lt;/a&gt; (480 logical shards across 32 instances), &lt;a href=&quot;https://instagram-engineering.com/sharding-ids-at-instagram-1cf5a71e5a5c&quot;&gt;Instagram&lt;/a&gt; (logical shards as Postgres schemas across a few dozen machines), and most large Postgres shops.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;4-routing-layers&quot;&gt;4. Routing Layers&lt;/h2&gt;
&lt;p&gt;Three styles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Application-level.&lt;/strong&gt; The app computes the shard and opens a connection to the right Postgres. Maximum control, maximum responsibility. Each shard is vanilla Postgres — same monitoring, same backups, same &lt;code&gt;psql&lt;/code&gt;. You write the fan-out logic, the directory cache, the rebalancing tools. Most large Postgres shops do this.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SQL-aware proxy&lt;/strong&gt; (PgCat, Citus’s coordinator, vendor proxies). One endpoint the app talks to; it parses queries, computes shards, fans out reads, merges results. Strengths: app stays simple. Weakness: the proxy has a worldview, and your queries have to fit it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Distributed Postgres-compatible databases&lt;/strong&gt; (CockroachDB, YugabyteDB). A different system that speaks the Postgres wire protocol. Covered in the Ecosystem section.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;5-the-hard-parts-and-there-are-a-lot-of-them&quot;&gt;5. The Hard Parts (And There Are a Lot of Them)&lt;/h2&gt;
&lt;p&gt;When teams build sharded Postgres for the first time, the first six months are mostly about the things they didn’t plan for. Here’s the catalogue. Each one is a project, not a paragraph — but you need to know all of them exist before you start.&lt;/p&gt;
&lt;h3 id=&quot;51-cross-shard-joins&quot;&gt;5.1 Cross-shard &lt;code&gt;JOIN&lt;/code&gt;s&lt;/h3&gt;
&lt;p&gt;A single Postgres &lt;code&gt;JOIN&lt;/code&gt; runs in microseconds because both sides of the join are on the same machine, in the same buffer cache. The moment you shard, a &lt;code&gt;JOIN&lt;/code&gt; between two tables that don’t share the same shard key becomes a &lt;strong&gt;fan-out&lt;/strong&gt; query: the app or proxy asks every shard for matching rows, ships them over the network, and merges the results.&lt;/p&gt;
&lt;p&gt;Concrete example. You have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;users&lt;/code&gt; sharded by &lt;code&gt;tenant_id&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;audit_logs&lt;/code&gt; sharded by &lt;code&gt;tenant_id&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A query like this stays on a single shard — Postgres handles it the same way it always did:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; u&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;l&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;action&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; users u&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;JOIN&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; audit_logs l &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ON&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; l&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;user_id&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; u&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;id&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; u&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;tenant_id&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 42&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But add a global feature: &lt;em&gt;“show every audit log entry across all tenants for users who signed up in the last 24 hours.”&lt;/em&gt; Now the routing layer has to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Query every shard for users who signed up in the last 24 hours.&lt;/li&gt;
&lt;li&gt;Group those user IDs by which shard they came from.&lt;/li&gt;
&lt;li&gt;Query every shard &lt;em&gt;again&lt;/em&gt; for matching audit log entries.&lt;/li&gt;
&lt;li&gt;Merge everything into one result set.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;With 32 shards that’s 64 round-trips, network latency added per call, partial-failure modes when one shard times out, and merge logic somewhere in the app. The fix is &lt;strong&gt;co-location&lt;/strong&gt; — design the schema so tables you’d join always share the shard key. The cost of co-location is that occasionally you’ll want a cross-tenant join and simply won’t have it.&lt;/p&gt;
&lt;h3 id=&quot;52-cross-shard-aggregations-and-reporting&quot;&gt;5.2 Cross-shard aggregations and reporting&lt;/h3&gt;
&lt;p&gt;Single-shard reads scale linearly with shard count. Cross-shard &lt;em&gt;aggregations&lt;/em&gt; don’t.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;“How many active users do we have?”&lt;/em&gt; is now &lt;code&gt;SELECT count(*) FROM users WHERE last_active &gt; now() - interval &apos;30 days&apos;&lt;/code&gt; on every shard, summed in the app. &lt;em&gt;“Top 10 products globally by revenue this month”&lt;/em&gt; is a partial sort on every shard followed by a global merge-sort.&lt;/p&gt;
&lt;p&gt;This is why every sharded company eventually builds a parallel analytics path — a data warehouse like Snowflake, BigQuery, Redshift, or ClickHouse, fed by Change Data Capture (CDC) streams from each shard. Operational queries hit Postgres; analytics queries hit the warehouse. You absorb the latency cost (warehouse data is minutes behind real-time) in exchange for queries that can scan globally.&lt;/p&gt;
&lt;p&gt;If you don’t plan for the warehouse before sharding, every reporting feature becomes a scatter-gather of doom and the analytics team starts asking why the dashboard takes 90 seconds to load.&lt;/p&gt;
&lt;h3 id=&quot;53-foreign-keys-disappear&quot;&gt;5.3 Foreign keys disappear&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;FOREIGN KEY&lt;/code&gt; in Postgres is the database telling you &lt;em&gt;“this &lt;code&gt;user_id&lt;/code&gt; must reference a real row in &lt;code&gt;users.id&lt;/code&gt;.”&lt;/em&gt; It’s enforced at write time — try to insert an order for a user who doesn’t exist and Postgres refuses.&lt;/p&gt;
&lt;p&gt;Across shards, this guarantee doesn’t exist. If &lt;code&gt;users&lt;/code&gt; and &lt;code&gt;orders&lt;/code&gt; live on different shards, Postgres has no way to check. Two ways to handle it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Co-locate the related tables.&lt;/strong&gt; If &lt;code&gt;orders&lt;/code&gt; and &lt;code&gt;users&lt;/code&gt; are both sharded by &lt;code&gt;tenant_id&lt;/code&gt;, the FK can be enforced normally within each shard’s vanilla Postgres. The constraint is local — and local is fine because &lt;em&gt;all&lt;/em&gt; the rows you care about for that tenant are on one shard.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enforce in application code.&lt;/strong&gt; Check that the parent exists before the insert. Accept the race condition (the parent could be deleted between check and insert, leaving an orphan) or guard it with application-level locking. Most teams accept the race because the failure mode — an orphan row — is recoverable, and the alternative is much more expensive.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;54-globally-unique-ids&quot;&gt;5.4 Globally unique IDs&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;bigserial&lt;/code&gt; and &lt;code&gt;SERIAL&lt;/code&gt; columns are backed by a &lt;em&gt;sequence&lt;/em&gt; — a per-database counter that increments on every insert. Sequences are local to each Postgres instance. Once you have N shards, two different shards will both happily emit &lt;code&gt;id = 1&lt;/code&gt; for the first inserted row, and now you have collisions everywhere.&lt;/p&gt;
&lt;p&gt;Three common fixes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;UUIDs.&lt;/strong&gt; Universally Unique Identifiers — 128-bit random values, unique by construction across any system. 16 bytes instead of 8, and the randomness defeats the locality optimizations that B-tree indexes use for inserts. v7 UUIDs (time-prefixed) are a good middle ground; standard v4 random UUIDs hurt insert performance because each new row lands on a random index page.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Snowflake-style IDs.&lt;/strong&gt; A 64-bit integer composed of &lt;code&gt;(timestamp_ms | shard_id | sequence_within_ms)&lt;/code&gt;. Fits in a &lt;code&gt;bigint&lt;/code&gt;, sorts roughly by time (good for indexes), unique by construction (different shards have different shard_id bits). Originally Twitter’s design, now copied widely.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Centralised ID service.&lt;/strong&gt; A single coordinator hands out ID ranges to each shard. Simple to reason about, but it’s now a hop on every insert and a single point of failure.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The decision matters far beyond ID generation. IDs are everywhere — in URLs, in logs, in cross-system traces. Choosing badly means migrating IDs later, which is much worse than migrating data.&lt;/p&gt;
&lt;h3 id=&quot;55-distributed-transactions&quot;&gt;5.5 Distributed transactions&lt;/h3&gt;
&lt;p&gt;A single Postgres transaction is atomic. This works fine on one machine:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;BEGIN&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;UPDATE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; accounts &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; balance &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; balance &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;UPDATE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; accounts &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; balance &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; balance &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;COMMIT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Either both updates apply or neither does. Across shards (say &lt;code&gt;id = 1&lt;/code&gt; is on shard A and &lt;code&gt;id = 2&lt;/code&gt; is on shard B), you have two bad options.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Two-Phase Commit (2PC).&lt;/strong&gt; A coordinator asks every participating shard &lt;em&gt;“can you commit?”&lt;/em&gt; Each shard &lt;em&gt;prepares&lt;/em&gt; the transaction (writes the changes durably but doesn’t make them visible) and replies. Once all shards say yes, the coordinator broadcasts &lt;em&gt;“commit.”&lt;/em&gt; Sounds clean. In practice, the prepare phase locks rows on every shard for the round-trip duration; if the coordinator crashes between phases, you have prepared transactions that can’t be resolved without manual intervention. Production sharded systems almost universally avoid 2PC.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sagas.&lt;/strong&gt; Break the cross-shard operation into a sequence of single-shard transactions, each with a compensating undo step. If a later step fails, run the inverse of the earlier steps.&lt;/p&gt;
&lt;p&gt;Concrete example — transferring $10 between two users on different shards:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Step 1:  shard A → debit user-1 by $10      (commit on shard A)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Step 2:  shard B → credit user-2 by $10     (commit on shard B)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;If Step 2 fails:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   Compensation → shard A → credit user-1 by $10&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The sequence has to be &lt;strong&gt;idempotent&lt;/strong&gt; (running step 2 twice must be the same as running it once), because retries are unavoidable in distributed systems. It has to handle the case where the compensation itself fails (you ledger the failure and route it to a human-review queue). And it has to be observable, so you can answer &lt;em&gt;“where is transfer #1234 stuck?”&lt;/em&gt; three weeks later when a customer complains.&lt;/p&gt;
&lt;p&gt;Stripe’s Ledger system is essentially a giant saga orchestrator on top of sharded storage. Done well, sagas are robust. Done badly, they’re a permanent source of data inconsistency.&lt;/p&gt;
&lt;h3 id=&quot;56-online-rebalancing&quot;&gt;5.6 Online rebalancing&lt;/h3&gt;
&lt;p&gt;Sooner or later one shard is too hot, a region is being added, or the original key choice was wrong for a workload that has since changed shape. You need to move data &lt;em&gt;while the application keeps reading and writing&lt;/em&gt;. There’s no maintenance window — the system is live.&lt;/p&gt;
&lt;p&gt;The pattern that has emerged across published architectures (Notion, Figma, Slack on Vitess, Stripe):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Double-write.&lt;/strong&gt; Application writes go to both the old shard and the new shard for every row in the migrating range. Reads still come from the old shard.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backfill.&lt;/strong&gt; Stream historical data from old to new using &lt;strong&gt;logical replication&lt;/strong&gt; (Postgres’s built-in publication/subscription) or a CDC tool like Debezium.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Verify.&lt;/strong&gt; Compare random samples between old and new. Run the application against the new shard in shadow mode — every read also queries the new shard, results are compared but the old shard’s response is what’s returned to the user.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cutover.&lt;/strong&gt; Flip reads to the new shard. Keep double-writing for a safety window — usually days — in case you need to roll back.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tear down.&lt;/strong&gt; Stop writing to the old shard. Eventually drop the data.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each step is hours-to-days at real scale. Each has subtle failure modes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Replication lag&lt;/em&gt; — the new shard is minutes behind because the backfill is competing with live writes.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Diverging writes&lt;/em&gt; — the double-write got applied to the new shard but not the old (network blip), or vice versa, and a row’s value differs between the two.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Idempotency edge cases&lt;/em&gt; — the same write got applied twice on one side because of a retry.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Teams that get this right build it once as a generic framework and reuse it for every subsequent rebalance. Teams that don’t end up doing the migration by hand the first three times, with a different bug each time.&lt;/p&gt;
&lt;h3 id=&quot;57-hot-shards-and-tenant-skew&quot;&gt;5.7 Hot shards and tenant skew&lt;/h3&gt;
&lt;p&gt;Eventually one shard becomes a latency outlier. The usual causes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One tenant grew 40× the average (Notion’s published numbers describe this happening repeatedly).&lt;/li&gt;
&lt;li&gt;A region with disproportionate traffic concentration (&lt;code&gt;us-east&lt;/code&gt; always lighting up).&lt;/li&gt;
&lt;li&gt;A “celebrity user” pattern — one row receiving thousands of reads per second because some piece of content is going viral.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mitigations are uniformly painful:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Split the giant tenant&lt;/strong&gt; across multiple shards. Breaks co-location, requires application changes, makes their data harder to back up coherently.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Isolate them on a dedicated shard&lt;/strong&gt; so their problems don’t affect other tenants. Operationally fine. But you’ve now admitted the architecture isn’t really “shard by tenant” — it’s “shard by tenant, except for the special ones.”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Application-level rate limiting&lt;/strong&gt; for the hot row or hot tenant. Buys time, doesn’t fix the underlying skew.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Caching layer&lt;/strong&gt; in front of the hot reads. Helps for read-heavy hot rows, doesn’t help if writes are the problem.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The lesson Notion and others have written about publicly: you can’t predict which tenant will go viral. Build the shard-migration tooling early, because you’ll need it.&lt;/p&gt;
&lt;h3 id=&quot;58-schema-migrations-across-n-shards&quot;&gt;5.8 Schema migrations across N shards&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ALTER TABLE&lt;/code&gt; on one Postgres is operationally simple. On 32 shards it’s a different problem.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The migration has to run on every shard. If it fails halfway through, some shards have the new schema and some don’t.&lt;/li&gt;
&lt;li&gt;The application code that depends on the new schema can’t roll out before the schema. So the schema change must be deployed &lt;em&gt;first&lt;/em&gt;, and it must be backward-compatible — the application still works against shards that haven’t migrated yet.&lt;/li&gt;
&lt;li&gt;The rollout takes minutes-to-hours, and during that window the application is running against shards in mixed states.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The pattern: every schema change is two PRs.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;PR 1&lt;/strong&gt; — make the schema change in a way the old code still works against. Add a new nullable column with a default; don’t drop the old column. Deploy. Run the migration on every shard.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PR 2&lt;/strong&gt; — once every shard has migrated and you’ve waited a deploy cycle, remove the old column and the now-unused code. Deploy that.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Expensive migrations (rewriting a 500 GB table) need &lt;code&gt;pg_repack&lt;/code&gt; or batched &lt;code&gt;UPDATE&lt;/code&gt; loops on each shard, with monitoring to catch the one shard where it fails partway through and resume from where it stopped. The thing you might be slightly lazy about on one Postgres becomes religion on N.&lt;/p&gt;
&lt;h3 id=&quot;59-backups-and-point-in-time-recovery&quot;&gt;5.9 Backups and point-in-time recovery&lt;/h3&gt;
&lt;p&gt;A single Postgres backup is &lt;code&gt;pg_basebackup&lt;/code&gt; plus an archived WAL stream. Point-in-time recovery (PITR) means &lt;em&gt;“restore to the state the database was in at 14:32:11 last Tuesday.”&lt;/em&gt; You replay WAL forward from the base backup until you reach that timestamp.&lt;/p&gt;
&lt;p&gt;On 32 shards, you have 32 base backups taken at 32 slightly different points in time, with 32 separate WAL streams. If you need to restore the &lt;em&gt;whole system&lt;/em&gt; to a globally consistent moment — say, before a bug corrupted data across multiple tenants — you need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Each shard’s base backup, taken near the same wall-clock time.&lt;/li&gt;
&lt;li&gt;Each shard’s archived WAL.&lt;/li&gt;
&lt;li&gt;Tooling that orchestrates a parallel restore across all 32 shards to the same target timestamp.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most teams accept the approximation: shards are restored to &lt;em&gt;near&lt;/em&gt; the same point in time, and any cross-shard inconsistencies introduced by the restore are reconciled manually after. True globally-consistent PITR on a sharded Postgres is hard enough that most teams don’t attempt it. They invest instead in audit logs and replay tools that can selectively undo a bad transaction.&lt;/p&gt;
&lt;h3 id=&quot;510-connection-pooling-explosion&quot;&gt;5.10 Connection pooling explosion&lt;/h3&gt;
&lt;p&gt;Your application talks to one Postgres? It opens N database connections. Talks to 32 shards? It potentially needs N × 32 connections, one pool per shard. With pgbouncer (a connection pooler) in front of each shard, the pgbouncer fleet is now managing 32× more connections too.&lt;/p&gt;
&lt;p&gt;Concrete numbers. Suppose your application server keeps 50 connections per Postgres. You have 100 application servers. With one database: 5,000 connections — already close to Postgres’s practical ceiling (~10,000) and a clear case for pgbouncer. With 32 shards: potentially 160,000 connections in the worst case. You’ll exhaust file descriptors before you exhaust the database.&lt;/p&gt;
&lt;p&gt;Solutions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lazy pools.&lt;/strong&gt; Only open a connection to a shard when a request actually needs it. Most requests touch one shard, so most pools stay small.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reverse routing.&lt;/strong&gt; Application servers are assigned to subsets of shards, so each server only pools connections to its assigned shards.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Shared connection pool layer.&lt;/strong&gt; A central pgbouncer cluster fronting all shards, sized for the global connection count rather than per-app.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You’ll discover this in production when traffic spikes against one shard exhaust its &lt;code&gt;max_connections&lt;/code&gt; and the application starts failing every request that needs that shard, regardless of which app server is doing the asking.&lt;/p&gt;
&lt;h3 id=&quot;511-failover-and-disaster-recovery&quot;&gt;5.11 Failover and disaster recovery&lt;/h3&gt;
&lt;p&gt;One Postgres going down = your app is down. 32 shards = one shard going down means 1/32 of users see errors. Better in some ways, worse in others.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Better:&lt;/strong&gt; the blast radius is smaller. Most users don’t notice. You have time to respond.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Worse:&lt;/strong&gt; failover has to be automated per shard because manual intervention doesn’t scale across 32 instances. Each shard needs a hot standby (a streaming replica ready to take over) and an automated promotion script. &lt;strong&gt;Patroni&lt;/strong&gt; or &lt;strong&gt;Stolon&lt;/strong&gt; are the two common tools for managing this.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Worse:&lt;/strong&gt; “is the database up?” is no longer a single health check. It’s 32. Your dashboards have to handle “27/32 healthy, 5 degraded” — and the routing layer has to route around the failing ones gracefully.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You also need to think about correlated failures. A bad query pattern or a bug in a schema migration can take down many shards simultaneously. “One shard at a time is fine” is a comforting story that doesn’t survive contact with reality.&lt;/p&gt;
&lt;h3 id=&quot;512-observability-becomes-32-harder&quot;&gt;5.12 Observability becomes 32× harder&lt;/h3&gt;
&lt;p&gt;A slow query on one shard is invisible on the dashboards for the other 31. The questions you ask change:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;“What’s the p99 query latency?”&lt;/em&gt; (the latency the slowest 1% of queries experience) → &lt;em&gt;“What’s the p99 latency per shard, and which shard is slowest?”&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Which queries are the worst offenders?”&lt;/em&gt; → &lt;em&gt;“Which queries, on which shards, and is it the same workload everywhere?”&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Disk usage?”&lt;/em&gt; → 32 numbers, hopefully one dashboard.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You need per-shard tagging in your metrics, log aggregation that can group by shard, and dashboards that surface the &lt;em&gt;outlier&lt;/em&gt; shard rather than averaging across all 32 (averages hide the one shard that’s on fire). The “show me the worst shard right now” view is the single most valuable dashboard a sharded system has.&lt;/p&gt;
&lt;h3 id=&quot;513-testing-and-dev-environments&quot;&gt;5.13 Testing and dev environments&lt;/h3&gt;
&lt;p&gt;Production has 32 shards. Your laptop has one Postgres. The bugs that only appear in production are exactly the ones related to the sharding boundary — cross-shard joins, routing logic, the saga compensation step you never exercised.&lt;/p&gt;
&lt;p&gt;Most teams settle on one of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Run a small number of shards locally&lt;/strong&gt; (2 or 4) to exercise the routing logic. Not a faithful reproduction, but catches most routing bugs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maintain a staging environment&lt;/strong&gt; that mirrors production at smaller scale and is the only place where the sharded code path is genuinely tested before production.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integration tests against a small sharded cluster in CI.&lt;/strong&gt; Slow but catches real bugs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Neither is great. Sharded systems have a long tail of “only-fails-in-production” bugs that you pay for through monitoring discipline and quick rollback rather than test coverage.&lt;/p&gt;
&lt;h3 id=&quot;514-multi-tenant-security-boundaries&quot;&gt;5.14 Multi-tenant security boundaries&lt;/h3&gt;
&lt;p&gt;When &lt;code&gt;tenant_id&lt;/code&gt; is the shard key, the database physically separates tenants. A query that forgets to filter by &lt;code&gt;tenant_id&lt;/code&gt; returns nothing useful, because that tenant’s data isn’t on the connected shard. This is accidentally good for security.&lt;/p&gt;
&lt;p&gt;But the inverse: if the routing layer has a bug that sends a query to the wrong shard, you’ve just leaked one tenant’s data to another. Routing-layer bugs become &lt;strong&gt;security incidents&lt;/strong&gt; in sharded systems in a way they aren’t in single-database systems. Teams that take this seriously add:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pre-flight assertions.&lt;/strong&gt; The application checks that the connection it’s about to use is the right shard for the tenant in the request context. Cheap and catches most bugs immediately.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Result validation.&lt;/strong&gt; Every query result is filtered through a check that &lt;em&gt;all&lt;/em&gt; returned rows match the expected &lt;code&gt;tenant_id&lt;/code&gt;. A row that doesn’t match means routing failed; the request is rejected and an alert fires.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Periodic audits.&lt;/strong&gt; Random sampling of query results to confirm no cross-tenant leakage in production.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;515-the-cost--in-dollars-and-headcount&quot;&gt;5.15 The cost — in dollars and headcount&lt;/h3&gt;
&lt;p&gt;Sharding multiplies your infrastructure cost roughly linearly with shard count. 32 shards is 32 Postgres instances, each with its own storage, backups, monitoring, hot standby. The savings come from using smaller machines per shard, but rarely fully offset the multiplier — you usually end up paying 1.5–3× what one giant machine would have cost.&lt;/p&gt;
&lt;p&gt;The bigger cost is &lt;strong&gt;headcount&lt;/strong&gt;. A team running one Postgres can treat it as part-time work for a thoughtful backend engineer. A team running 32 shards needs at least one full-time database engineer thinking about capacity, rebalancing, failover, and the migration framework. The platform is now a product — with an on-call rotation, a roadmap, and an expectation that someone owns it 24/7.&lt;/p&gt;
&lt;p&gt;This is the hidden tax of premature sharding: you’re permanently adding a person (or three) to your headcount in exchange for a problem you might not have actually had yet.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;6-what-sharding-actually-does-to-postgres&quot;&gt;6. What Sharding Actually Does to Postgres&lt;/h2&gt;
&lt;p&gt;The two strategies (partitioning and sharding) route around fundamentally different bottlenecks. Partitioning shrinks the &lt;em&gt;active working set&lt;/em&gt; and gives operations a smaller object to grip. Sharding adds &lt;em&gt;physical resources&lt;/em&gt; — more disks, more cores, more RAM, more &lt;code&gt;max_connections&lt;/code&gt; — at the cost of coordination.&lt;/p&gt;
&lt;h3 id=&quot;wal--the-resource-sharding-actually-adds&quot;&gt;WAL — the resource sharding actually adds&lt;/h3&gt;
&lt;p&gt;Postgres writes every change to the Write-Ahead Log before modifying the heap. All writes across all partitions go to the same WAL on the same physical disk, serialized through &lt;code&gt;XLogInsert&lt;/code&gt; and ultimately one &lt;code&gt;fsync&lt;/code&gt; per group commit. There is one WAL per Postgres cluster.&lt;/p&gt;
&lt;p&gt;This is the throughput ceiling partitioning can’t break. A modern NVMe disk fsyncs in tens of microseconds; with synchronous commit and a busy backend you can push tens of thousands of WAL records per second per instance, but you don’t get to add more WAL by adding partitions. Sharding spreads WAL across N machines and N disks — this is the actual write-scaling mechanism.&lt;/p&gt;
&lt;h3 id=&quot;replication&quot;&gt;Replication&lt;/h3&gt;
&lt;p&gt;A streaming replica replays WAL serially. When the primary writes WAL faster than the replica can apply, lag &lt;em&gt;expands&lt;/em&gt; under load. Postgres 16+ has parallel apply for some WAL record types, but the constraint stands: one replica can’t keep up with a primary running on hardware many times its size. Sharding turns “one fast primary, one struggling replica” into “N modest primaries, each with a comfortable replica.”&lt;/p&gt;
&lt;h3 id=&quot;connections&quot;&gt;Connections&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;max_connections&lt;/code&gt; is per-cluster, and each backend is a heavyweight process. The practical ceiling is a few thousand — beyond which you’re using pgbouncer in transaction-pooling mode and accepting its tradeoffs (no session state, fewer prepared statements, no &lt;code&gt;LISTEN&lt;/code&gt;/&lt;code&gt;NOTIFY&lt;/code&gt;). Sharding multiplies the ceiling by shard count.&lt;/p&gt;
&lt;h3 id=&quot;checkpoints&quot;&gt;Checkpoints&lt;/h3&gt;
&lt;p&gt;The checkpointer flushes dirty buffers and trims the WAL every 5 minutes or 1 GB, whichever first. On a single instance with TB of data and a hot working set, every checkpoint is an I/O spike that shows up in tail latency. Sharding spreads checkpoints across machines so they’re no longer correlated.&lt;/p&gt;
&lt;p&gt;The shape of this: &lt;strong&gt;sharding solves problems that are about per-cluster physical resources.&lt;/strong&gt; If your problem isn’t physical resources, sharding adds a lot of complexity without buying you anything. Partition first; vertical-decompose second; shard only when nothing cheaper is left.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;7-the-postgres-ecosystem&quot;&gt;7. The Postgres Ecosystem&lt;/h2&gt;
&lt;p&gt;The tools that show up everywhere in production sharded Postgres:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/citusdata/citus&quot;&gt;&lt;strong&gt;Citus&lt;/strong&gt;&lt;/a&gt; — turns one coordinator and N worker nodes into a distributed Postgres. Define a distribution column; Citus rewrites queries to fan out and merge results. Co-located tables join efficiently. Owned by Microsoft now, powers Azure Cosmos DB for PostgreSQL. Best fit when the workload has a clear distribution column and most queries already filter by it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.postgresql.org/docs/current/logical-replication.html&quot;&gt;&lt;strong&gt;Logical replication&lt;/strong&gt;&lt;/a&gt; — Postgres’s publication/subscription system streams row changes (not WAL bytes) to subscribers. The mechanism behind every serious online shard migration, every &lt;a href=&quot;https://debezium.io/&quot;&gt;Debezium&lt;/a&gt;-based CDC pipeline, and tools like &lt;code&gt;pg_easy_replicate&lt;/code&gt; for upgrades.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Distributed Postgres-compatible databases&lt;/strong&gt; — &lt;a href=&quot;https://www.cockroachlabs.com/&quot;&gt;CockroachDB&lt;/a&gt;, &lt;a href=&quot;https://www.yugabyte.com/&quot;&gt;YugabyteDB&lt;/a&gt;. Not Postgres, but speak its wire protocol. Strong consistency via Raft, automatic resharding, multi-region support. The catch: write latency is higher (consensus isn’t free), some PG features are missing or partial (certain extensions, advisory locks, custom types, some JSONB operators). Right answer for new systems needing multi-region transactional writes from day one; harder sell as a migration target for a mature Postgres workload.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Patroni / Stolon&lt;/strong&gt; — automated failover managers for Postgres clusters. Essential for running 32 shards each with a hot standby — manual failover does not scale.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;8-failure-modes-specific-to-sharding&quot;&gt;8. Failure Modes Specific to Sharding&lt;/h2&gt;
&lt;p&gt;Beyond the hard parts above, here are the incident-report patterns you’ll see most often in mature sharded systems.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Uneven shard distribution.&lt;/strong&gt; You sharded by &lt;code&gt;tenant_id&lt;/code&gt; and one tenant is 40× the average. That shard is the bottleneck; everyone else is bored. Splitting the giant tenant breaks co-location; isolating it on a dedicated shard works but admits the architecture isn’t really “shard by tenant” anymore.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Painful rebalancing.&lt;/strong&gt; Shard 7 moving to a new machine. Double-write on, backfill at 80%, a bug in the comparison job silently passing diverging writes through. You discover it after cutover. Two sources of truth and a Saturday.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cross-shard transactions, snuck in.&lt;/strong&gt; A feature needed atomic updates across two tenants. You don’t have 2PC. The code stitched together unrelated commits, and now an orphan in shard B points to a missing parent in shard A. The second-worst class of bug in sharded systems. (The worst: silent divergence during a rebalance.)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Schema migrations that aren’t backward-compatible.&lt;/strong&gt; You dropped a column and the code that read it in one PR — but the rollout is shard-by-shard, and now some shards have the new schema and some don’t. Always two-step: schema-compatible change first, code change second, after every shard has migrated.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The slow shard nobody noticed.&lt;/strong&gt; Per-shard metrics exist but the dashboard averages across all of them. One shard is at p99 = 2 seconds; the global average is fine; nobody notices until a customer complains. The single most valuable sharded-system dashboard is the &lt;em&gt;outlier&lt;/em&gt; view, not the average.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;9-the-full-scaling-journey&quot;&gt;9. The Full Scaling Journey&lt;/h2&gt;
&lt;p&gt;What actually happens, in order, in systems that reach interesting scale:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stage 0 — One Postgres.&lt;/strong&gt; Tune &lt;code&gt;shared_buffers&lt;/code&gt; (~25% of RAM), &lt;code&gt;work_mem&lt;/code&gt;, &lt;code&gt;effective_io_concurrency&lt;/code&gt;, autovacuum cost limits. Add the right indexes. Use &lt;code&gt;EXPLAIN ANALYZE&lt;/code&gt;. Orders of magnitude on the table.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stage 1 — Read replicas.&lt;/strong&gt; Send analytical and reporting traffic to followers. Buys read scale, not writes. Replicas aren’t transactionally consistent with the primary; design around it or pay write latency for synchronous replication.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stage 2 — Partition the hot tables.&lt;/strong&gt; Range-partition the 4 TB events table by day or month. Drop old partitions on a cron. Same for audit logs, activity streams, anything append-mostly. Often buys 2–5 years of runway. (Covered in detail in the sibling post: &lt;strong&gt;&lt;a href=&quot;/blog/postgres-partitioning/&quot;&gt;Postgres Partitioning&lt;/a&gt;&lt;/strong&gt;.)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stage 3 — Vertical decomposition.&lt;/strong&gt; Pull large independent domains into their own Postgres instances: &lt;code&gt;billing&lt;/code&gt;, &lt;code&gt;analytics&lt;/code&gt;, &lt;code&gt;notifications&lt;/code&gt;, &lt;code&gt;search&lt;/code&gt;. Multiple connection pools, but each database is still single-node. This is where most companies stop.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stage 4 — Shard the core.&lt;/strong&gt; When central tenant/user data still won’t fit, pick a partition key (almost always &lt;code&gt;tenant_id&lt;/code&gt;), pick a logical shard count, build the routing layer, migrate over a quarter using double-write. Build the runbooks. Hire a database team.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stage 5 — Operate the platform.&lt;/strong&gt; Sharding isn’t a project, it’s a regime. Per-shard observability, capacity planning, rebalancing tooling, migration automation. The sharding system &lt;em&gt;is&lt;/em&gt; a product.&lt;/p&gt;
&lt;p&gt;The mistake is jumping from Stage 1 to Stage 4. Avoid premature sharding the same way you’d avoid premature microservices: the costs are paid forever, the benefits arrive later than expected, and most wins were available cheaper one layer up.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;10-the-insight&quot;&gt;10. The Insight&lt;/h2&gt;
&lt;p&gt;Partitioning is usually about &lt;strong&gt;making one database manageable&lt;/strong&gt;. Sharding is about &lt;strong&gt;admitting one database is no longer enough&lt;/strong&gt;. They’re not points on the same continuum — they’re answers to different questions, taken from different toolkits, costing different things, paid forever.&lt;/p&gt;
&lt;p&gt;The teams that scale Postgres well are not the teams who shard early. They’re the teams who partition aggressively, decompose their data domains, build serious observability around their one cluster, and only reach for sharding when they’ve genuinely exhausted what one big machine can do. By the time they do shard, the architecture has been forced into a shape that &lt;em&gt;can&lt;/em&gt; be sharded — a clear partition key emerging from the query patterns, related data co-located by accident of the data model, transactional boundaries that already respect tenant edges.&lt;/p&gt;
&lt;p&gt;The architecture that survives is the one you can still understand at 3 AM with a single &lt;code&gt;psql&lt;/code&gt; window open. Postgres makes that achievable longer than most people think, if you use partitioning well, vertical decomposition deliberately, and sharding only when nothing cheaper is left.&lt;/p&gt;
&lt;p&gt;This is the first post in the Distributed Systems series. Next up: replication strategies — synchronous vs asynchronous, physical vs logical, and the consistency tradeoffs each forces on the application above it. After that: consensus protocols (Raft and friends), distributed transactions (2PC, sagas, the outbox pattern), CDC pipelines, and distributed locks. Sharding was the easy one; the rest of this is about coordinating machines that don’t share memory and can’t fully trust each other.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;related-reading&quot;&gt;Related reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/postgres-partitioning/&quot;&gt;Postgres Partitioning: Strategies, Advantages, and Pitfalls&lt;/a&gt; — the cheaper step you should exhaust before sharding.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/postgres-replication/&quot;&gt;Database Replication: What to Use When&lt;/a&gt; — Part 2 of this series; covers single-leader, multi-leader, leaderless, and the consistency tradeoffs.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/acid-properties-and-isolation-levels/&quot;&gt;ACID, Read Phenomena, and Isolation Levels&lt;/a&gt; — what cross-shard transactions cost you compared to single-node.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/postgres-explain/&quot;&gt;Reading PostgreSQL EXPLAIN Output&lt;/a&gt; — useful for the partitioning step and for diagnosing slow per-shard queries.&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>The Crypto Module: Hashing, Encryption, and What to Use When</title><link>https://abhimanyunagurkar.com/blog/crypto-module-guide/</link><guid isPermaLink="true">https://abhimanyunagurkar.com/blog/crypto-module-guide/</guid><description>A practical guide to cryptography primitives available in every language — hashing, salting, HMAC, AES encryption, and secure random. Know what to use when.</description><pubDate>Mon, 11 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Every serious programming language ships a &lt;code&gt;crypto&lt;/code&gt; module in its standard library. Go has &lt;code&gt;crypto/*&lt;/code&gt;. Node.js has &lt;code&gt;node:crypto&lt;/code&gt;. Python has &lt;code&gt;hashlib&lt;/code&gt; and &lt;code&gt;secrets&lt;/code&gt;. They all expose the same underlying primitives — but using the wrong one for the job can silently destroy your security.&lt;/p&gt;
&lt;p&gt;This post maps the terminology to the concepts, shows you what each primitive actually does, and gives you a clear decision tree for common scenarios.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-vocabulary-defined-once-used-everywhere&quot;&gt;The Vocabulary (Defined Once, Used Everywhere)&lt;/h2&gt;
&lt;p&gt;Before touching code, let’s fix the words. A lot of crypto confusion comes from these terms being used interchangeably when they shouldn’t be.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Encoding&lt;/strong&gt; — transforms data into a different representation. Base64, hex, URL-encoding. Reversible. Provides &lt;em&gt;zero&lt;/em&gt; security — it’s not encryption.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hashing&lt;/strong&gt; — a one-way transformation. Input of any size → fixed-size output (the &lt;strong&gt;digest&lt;/strong&gt;). Practically impossible to reverse. The same input always produces the same digest.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Encryption&lt;/strong&gt; — a two-way transformation. Requires a key. You can decrypt back to the original if you have the key.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Digest&lt;/strong&gt; — the output of a hash function. &lt;code&gt;SHA-256(&quot;hello&quot;)&lt;/code&gt; → a 32-byte digest, usually shown as 64 hex characters.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Salt&lt;/strong&gt; — random data mixed with a password before hashing it, so identical passwords produce different digests. Defeats precomputed rainbow-table attacks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HMAC&lt;/strong&gt; — Hash-based Message Authentication Code. A hash that requires a secret key to produce and verify. Proves both integrity and authenticity.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key Derivation Function (KDF)&lt;/strong&gt; — a deliberately slow hash designed specifically for passwords. Bcrypt, Argon2, PBKDF2 are KDFs. Slowness is the feature — it makes brute-force expensive.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pepper&lt;/strong&gt; — a server-side secret (e.g. in an environment variable) mixed into every password hash. Stored separately from the database, so a DB leak alone isn’t enough to crack hashes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IV / Nonce&lt;/strong&gt; — Initialisation Vector / Number Used Once. Random bytes fed into an encryption operation so that encrypting the same plaintext twice produces different ciphertexts.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;hashing-integrity-not-secrecy&quot;&gt;Hashing: Integrity, Not Secrecy&lt;/h2&gt;
&lt;p&gt;Use a hash when you need to verify that data hasn’t changed, or to produce a fixed-size fingerprint of something.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it’s good for:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Checksums on file downloads&lt;/li&gt;
&lt;li&gt;Deduplication (content-addressable storage)&lt;/li&gt;
&lt;li&gt;Building blocks for HMAC and KDFs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;What it is NOT for:&lt;/strong&gt; storing passwords, or anything where the data needs to be kept secret.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Go&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;crypto/sha256&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;data &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; []&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;byte&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;important document&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;digest &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; sha256.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Sum256&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(data)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;fmt.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Printf&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;%x\n&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, digest) &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// 64 hex chars&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Node.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; { createHash } &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;node:crypto&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; digest&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; createHash&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;sha256&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  .&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;update&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;important document&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  .&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;digest&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;hex&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(digest); &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// 64 hex chars&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Which algorithm to use:&lt;/strong&gt;&lt;/p&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Algorithm&lt;/th&gt;&lt;th&gt;Status&lt;/th&gt;&lt;th&gt;Use for&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;SHA-256&lt;/td&gt;&lt;td&gt;✅ Safe&lt;/td&gt;&lt;td&gt;General-purpose checksums, HMAC, signatures&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;SHA-512&lt;/td&gt;&lt;td&gt;✅ Safe&lt;/td&gt;&lt;td&gt;Same as SHA-256, larger output&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;SHA-3&lt;/td&gt;&lt;td&gt;✅ Safe&lt;/td&gt;&lt;td&gt;Rarely needed; useful when SHA-2 is disallowed by policy&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;MD5&lt;/td&gt;&lt;td&gt;❌ Broken&lt;/td&gt;&lt;td&gt;Nothing security-related. Legacy file checksums only&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;SHA-1&lt;/td&gt;&lt;td&gt;❌ Broken&lt;/td&gt;&lt;td&gt;Nothing security-related&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;MD5 and SHA-1 are collision-vulnerable — two different inputs can produce the same digest. Never use them where security matters. Legacy systems still use them for non-security checksums (git uses SHA-1 for object IDs, for instance), but that doesn’t make them acceptable for new code dealing with passwords or signatures.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Practical example: package and image integrity.&lt;/strong&gt; When you &lt;code&gt;npm install&lt;/code&gt;, npm verifies every downloaded tarball against a SHA-256 hash recorded in &lt;code&gt;package-lock.json&lt;/code&gt;. If a byte differs — because the file was corrupted mid-download or because a malicious registry served a swapped tarball — the install fails before any code runs. The same pattern is everywhere: Docker pulls verify the &lt;code&gt;sha256:abc123…&lt;/code&gt; digest of each image layer, &lt;code&gt;apt&lt;/code&gt; checks SHA-256 sums in its &lt;code&gt;Packages.gz&lt;/code&gt; index, and download pages publish hashes so you can run &lt;code&gt;sha256sum file.iso&lt;/code&gt; locally and compare. The hash isn’t secret; it’s a public fingerprint that lets anyone detect tampering.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;salting-and-password-hashing&quot;&gt;Salting and Password Hashing&lt;/h2&gt;
&lt;p&gt;The single most common crypto mistake engineers make: hashing a password with &lt;code&gt;SHA-256&lt;/code&gt; directly.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// ❌ WRONG — never do this&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;hash &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; sha256.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Sum256&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;([]&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;byte&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;mypassword&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The problem: &lt;code&gt;SHA-256(&quot;password123&quot;)&lt;/code&gt; is the same hash for every user with that password. An attacker with a precomputed table of common password hashes (a &lt;strong&gt;rainbow table&lt;/strong&gt;) can reverse millions of hashes instantly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The fix: use a purpose-built key derivation function (KDF).&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;salt&lt;/strong&gt; is a random value mixed with the password before hashing, so identical passwords produce different digests.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;KDF&lt;/strong&gt; is a hash function deliberately designed to be slow — it makes brute-force attacks expensive. Good KDFs (bcrypt, Argon2id) generate and manage the salt for you automatically; you don’t store the salt separately.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Go — bcrypt handles salt generation internally&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;golang.org/x/crypto/bcrypt&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// when user signs up:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;hash, err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; bcrypt.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;GenerateFromPassword&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;([]&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;byte&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;mypassword&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;), bcrypt.DefaultCost)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// when user logs in:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; bcrypt.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;CompareHashAndPassword&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(hash, []&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;byte&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;mypassword&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // password matches&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Node.js — use the bcryptjs or @node-rs/bcrypt package&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; bcrypt &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;bcryptjs&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// signup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; hash&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; bcrypt.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;hash&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;mypassword&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;12&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// 12 = cost factor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// login&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; ok&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; bcrypt.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;compare&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;mypassword&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, hash);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output looks like &lt;code&gt;$2a$12$xyz...&lt;/code&gt; — the format embeds the algorithm, cost factor, salt, and hash all together. You store this single string and never need to manage the salt separately.&lt;/p&gt;
&lt;h3 id=&quot;what-is-the-cost-factor&quot;&gt;What is the cost factor?&lt;/h3&gt;
&lt;p&gt;The &lt;strong&gt;cost factor&lt;/strong&gt; (sometimes called work factor) controls how slow the KDF is. It’s not a linear multiplier — in bcrypt it’s an exponent: cost 12 means 2¹² = 4,096 internal iterations; cost 13 means 8,192. Each increment roughly doubles the time.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cost 10 → ~80ms   per hash  (too fast for high-security systems today)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cost 12 → ~300ms  per hash  (good default)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cost 13 → ~600ms  per hash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cost 14 → ~1200ms per hash&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The right cost factor is the highest one your system can afford without making login feel sluggish. A rule of thumb: aim for &lt;strong&gt;200–500ms&lt;/strong&gt; on your production hardware, and recalibrate every few years as hardware gets faster.&lt;/p&gt;
&lt;p&gt;For &lt;strong&gt;PBKDF2&lt;/strong&gt; (Password-Based Key Derivation Function 2), the equivalent knob is the &lt;strong&gt;iteration count&lt;/strong&gt; — the same principle applies: more iterations = more time = harder to brute-force.&lt;/p&gt;
&lt;p&gt;For Argon2id, you tune &lt;strong&gt;time cost&lt;/strong&gt; (iterations), &lt;strong&gt;memory cost&lt;/strong&gt; (RAM), and &lt;strong&gt;parallelism&lt;/strong&gt;. OWASP recommends a starting point of &lt;code&gt;m=64MB, t=1, p=1&lt;/code&gt; and increasing memory until you hit your latency budget.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;KDF comparison:&lt;/strong&gt;&lt;/p&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;KDF&lt;/th&gt;&lt;th&gt;Recommended cost&lt;/th&gt;&lt;th&gt;Memory-hard?&lt;/th&gt;&lt;th&gt;Notes&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Argon2id&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;default params&lt;/td&gt;&lt;td&gt;✅ Yes&lt;/td&gt;&lt;td&gt;Best choice for new systems&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;bcrypt&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;cost ≥ 12&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;Widely supported, still fine&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;PBKDF2-SHA256&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;≥ 600,000 iterations&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;FIPS-compliant environments&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;SHA-256 alone&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;—&lt;/td&gt;&lt;td&gt;—&lt;/td&gt;&lt;td&gt;❌ Never for passwords&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Memory-hard means the algorithm requires a lot of RAM, not just CPU time. This makes GPU-based brute-force attacks much more expensive — a GPU can run millions of SHA-256 operations per second in parallel, but struggles when each operation needs gigabytes of memory.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Bcrypt gotcha:&lt;/strong&gt; bcrypt silently truncates passwords longer than 72 bytes. A user with a 100-character passphrase only gets the first 72 hashed. If you allow long passwords, either pre-hash with SHA-256 before passing to bcrypt, or use Argon2id which has no length limit.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;when-not-to-salt&quot;&gt;When NOT to salt&lt;/h3&gt;
&lt;p&gt;Salt is valuable for low-entropy inputs like passwords where precomputed tables are a realistic attack. Skip it when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Input is already high-entropy&lt;/strong&gt; — API keys, UUIDs, cryptographic tokens (128-bit random values). Precomputing 2¹²⁸ hashes is impossible; salt adds nothing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;File integrity checksums&lt;/strong&gt; — &lt;code&gt;SHA-256&lt;/code&gt; of a file download exists to be verified against a published hash. A salt would change the digest and break the comparison.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Content-addressable storage / deduplication&lt;/strong&gt; — git object IDs, IPFS CIDs. The entire point is that identical content produces identical hashes. Salt breaks this by design.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HMAC&lt;/strong&gt; — the secret key already plays the role of salt (and provides authentication on top). A separate salt is redundant.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deterministic lookup&lt;/strong&gt; — if you need to query “does this value exist?” against stored hashes (e.g. checking whether an email is already registered), per-record salts prevent direct comparison. You’d need a server-side secret applied consistently to all records (a &lt;strong&gt;pepper&lt;/strong&gt;) rather than a random per-record salt.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The one-line rule: &lt;strong&gt;salt when the input space is small enough for an attacker to precompute hashes for; skip salt when the input is already unpredictable, or when identical-input → identical-hash is a requirement.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;hmac-signed-hashes&quot;&gt;HMAC: Signed Hashes&lt;/h2&gt;
&lt;p&gt;A plain hash proves the content hasn’t been corrupted. But it doesn’t prove &lt;em&gt;who&lt;/em&gt; produced it. An attacker who intercepts a payload can recompute the hash after modifying the data.&lt;/p&gt;
&lt;p&gt;HMAC adds a secret key to the mix. Only someone who knows the key can produce or verify the &lt;strong&gt;MAC&lt;/strong&gt; (Message Authentication Code).&lt;/p&gt;
&lt;p&gt;Both sides share the secret key. The sender signs, the receiver re-signs the same message and compares.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Go&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;crypto/hmac&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;crypto/sha256&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;encoding/hex&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; sharedKey &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; []&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;byte&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;my-secret-key&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// SENDER: sign and transmit (message, signature)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; sign&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; []&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;byte&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    mac &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; hmac.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;New&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(sha256.New, sharedKey)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    mac.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Write&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(message)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; hex.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;EncodeToString&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(mac.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Sum&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// RECEIVER: recompute and compare in constant time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; verify&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; []&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;byte&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;receivedSig&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    mac &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; hmac.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;New&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(sha256.New, sharedKey)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    mac.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Write&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(message)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    expected &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; mac.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Sum&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    actual, err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; hex.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;DecodeString&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(receivedSig)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; hmac.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Equal&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(expected, actual) &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// constant-time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Node.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; { createHmac, timingSafeEqual } &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;node:crypto&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; SECRET&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;my-secret-key&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; sign&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; createHmac&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;sha256&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;SECRET&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;update&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(message).&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;digest&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;hex&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; verify&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;receivedSig&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; expected&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; createHmac&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;sha256&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;SECRET&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;update&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(message).&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;digest&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; actual&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;   =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; Buffer.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(receivedSig, &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;hex&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (actual.&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; !==&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; expected.&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; timingSafeEqual&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(expected, actual);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Use HMAC for:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;API request signing (webhook signatures from Stripe, GitHub, etc.)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JWT&lt;/strong&gt; (JSON Web Token) secrets — the &lt;code&gt;HS256&lt;/code&gt; algorithm &lt;em&gt;is&lt;/em&gt; HMAC-SHA256&lt;/li&gt;
&lt;li&gt;Signed cookies or session tokens&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Practical example: verifying a Stripe webhook.&lt;/strong&gt; When a payment succeeds, Stripe POSTs a JSON event to your endpoint and includes a &lt;code&gt;Stripe-Signature&lt;/code&gt; HTTP header containing an HMAC-SHA256 of the raw request body, computed with a webhook secret that you and Stripe both hold. Your handler reads the secret from your environment, recomputes the HMAC over the exact bytes of the request body, and compares it to the header value using a constant-time check. If they match, you know two things: the request actually came from Stripe (nobody else has the secret), and the body wasn’t altered in transit. Without this verification, anyone who learns your webhook URL could send fake &lt;code&gt;payment.succeeded&lt;/code&gt; events and trick your app into shipping products for free.&lt;/p&gt;
&lt;h3 id=&quot;why-constant-time-comparison-matters&quot;&gt;Why constant-time comparison matters&lt;/h3&gt;
&lt;p&gt;When you compare two strings with &lt;code&gt;===&lt;/code&gt;, most implementations short-circuit — they stop at the first byte that differs and return false immediately. This creates a tiny but measurable timing difference: a signature that matches the first 20 bytes takes slightly longer to reject than one that matches 0 bytes.&lt;/p&gt;
&lt;p&gt;An attacker who can send millions of requests and measure response times can exploit this. They try signatures that differ one byte at a time, watching for the requests that take slightly longer. Eventually they can reconstruct the correct signature one byte at a time — without ever knowing the secret key. This is called a &lt;strong&gt;timing attack&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;hmac.Equal&lt;/code&gt; in Go and &lt;code&gt;timingSafeEqual&lt;/code&gt; in Node always take the same amount of time regardless of how many bytes match. The comparison never short-circuits. That removes the timing signal entirely.&lt;/p&gt;
&lt;h3 id=&quot;when-not-to-use-hmac&quot;&gt;When NOT to use HMAC&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;For data integrity alone over HTTPS, between services you control&lt;/strong&gt; — if you’re calling your own internal service over &lt;strong&gt;TLS&lt;/strong&gt; (Transport Layer Security, the protocol behind HTTPS), the TLS layer already provides integrity. Adding HMAC is redundant. (But for webhooks like Stripe → your endpoint, HMAC is still needed — HTTPS only proves the data wasn’t tampered with in transit, not that the &lt;em&gt;sender&lt;/em&gt; is Stripe specifically.)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When the other party doesn’t share your key&lt;/strong&gt; — HMAC requires both sides to know the secret. If you need to prove identity to a third party who doesn’t have your key (e.g. a public API client), use asymmetric signatures (RS256, ES256) instead.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;For password storage&lt;/strong&gt; — HMAC is not a key derivation function. Don’t use it to hash passwords; use bcrypt or Argon2id.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;encryption-aes-256-gcm&quot;&gt;Encryption: AES-256-GCM&lt;/h2&gt;
&lt;p&gt;When you need to encrypt data and decrypt it later (unlike hashing, which is one-way), use &lt;strong&gt;AES-256-GCM&lt;/strong&gt;. This is the current industry standard for symmetric encryption.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AES-256&lt;/strong&gt;: &lt;strong&gt;Advanced Encryption Standard&lt;/strong&gt; with a 256-bit key. Extremely fast on modern hardware (dedicated AES instructions exist in every modern CPU).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GCM mode&lt;/strong&gt;: Galois/Counter Mode. It gives you both &lt;strong&gt;confidentiality&lt;/strong&gt; (nobody can read the data) and &lt;strong&gt;integrity&lt;/strong&gt; (nobody can tamper with it without detection). This combination is called &lt;strong&gt;AEAD&lt;/strong&gt; (Authenticated Encryption with Associated Data) — “Associated Data” is optional unencrypted metadata, like a record ID, that you want authenticated alongside the ciphertext but not hidden.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Go&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;crypto/aes&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;crypto/cipher&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;crypto/rand&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;io&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; encrypt&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;plaintext&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; []&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;byte&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) ([]&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;byte&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    block, _ &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; aes.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;NewCipher&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(key)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    gcm, _ &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; cipher.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;NewGCM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(block)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    nonce &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; make&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;([]&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;byte&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, gcm.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;NonceSize&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// 12 bytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    io.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;ReadFull&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(rand.Reader, nonce)        &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// cryptographically random&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // nonce is prepended to ciphertext so decryption can extract it&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; gcm.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Seal&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(nonce, nonce, plaintext, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;nil&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; decrypt&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;ciphertext&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; []&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;byte&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) ([]&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;byte&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    block, _ &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; aes.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;NewCipher&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(key)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    gcm, _ &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; cipher.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;NewGCM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(block)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    nonce &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ciphertext[:gcm.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;NonceSize&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    data  &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ciphertext[gcm.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;NonceSize&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;():]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; gcm.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Open&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, nonce, data, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Node.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; { randomBytes, createCipheriv, createDecipheriv } &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;node:crypto&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; encrypt&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;plaintext&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; nonce&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; randomBytes&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;12&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; cipher&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; createCipheriv&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;aes-256-gcm&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, key, nonce);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; encrypted&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; Buffer.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;concat&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;([cipher.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;update&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(plaintext), cipher.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;final&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; tag&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; cipher.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;getAuthTag&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(); &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// 16-byte auth tag&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; Buffer.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;concat&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;([nonce, tag, encrypted]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; decrypt&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; nonce&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;      =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; data.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;subarray&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;12&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; tag&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;        =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; data.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;subarray&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;12&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;28&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; ciphertext&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; data.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;subarray&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;28&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; decipher&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;   =&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; createDecipheriv&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;aes-256-gcm&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, key, nonce);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  decipher.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;setAuthTag&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(tag);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; Buffer.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;concat&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;([decipher.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;update&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(ciphertext), decipher.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;final&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;what-is-a-nonce&quot;&gt;What is a nonce?&lt;/h3&gt;
&lt;p&gt;A &lt;strong&gt;nonce&lt;/strong&gt; (Number Used Once) is a random value you generate fresh for every single encryption. Think of it like a unique order number on an invoice — every invoice gets a different number, even if the contents are identical.&lt;/p&gt;
&lt;p&gt;AES-GCM uses a 12-byte (96-bit) nonce. It is not secret — the decryptor needs it to decrypt, so it’s stored alongside the ciphertext. The only requirement is that it must be unique per encryption with a given key. That’s why you generate it with a CSPRNG rather than counting up from 0 (a counter can work but is error-prone to manage).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What happens if you reuse a nonce?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;AES-GCM works by generating a keystream from the key and nonce, then XOR-ing your plaintext with it. If you encrypt two different messages with the same key and nonce, an attacker can XOR the two ciphertexts together — the keystream cancels out and they’re left with the XOR of the two plaintexts. Recovering readable content from that is often straightforward. Worse, the authentication tag (see below) becomes forgeable. This is called a &lt;strong&gt;two-time pad&lt;/strong&gt; attack and it’s completely catastrophic.&lt;/p&gt;
&lt;p&gt;The fix is trivial: always call &lt;code&gt;randomBytes(12)&lt;/code&gt; or &lt;code&gt;rand.Reader&lt;/code&gt; fresh for each encryption. Don’t save and reuse a nonce from a previous session.&lt;/p&gt;
&lt;h3 id=&quot;what-is-the-auth-tag&quot;&gt;What is the auth tag?&lt;/h3&gt;
&lt;p&gt;GCM produces a 16-byte &lt;strong&gt;authentication tag&lt;/strong&gt; alongside the ciphertext. It’s a signature over the ciphertext, computed using the key and nonce. When you decrypt, GCM recomputes the tag and compares it to the stored one. If any byte of the ciphertext was modified — by an attacker, by corruption, by anything — the tags won’t match and decryption fails with an error.&lt;/p&gt;
&lt;p&gt;This is why AES-GCM gives you both confidentiality &lt;em&gt;and&lt;/em&gt; integrity in one operation. You don’t need a separate HMAC on top of an AES-GCM ciphertext.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rules:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Generate a new random nonce for every encryption.&lt;/strong&gt; Reusing a nonce with the same key in GCM mode is catastrophic — it breaks both confidentiality and integrity.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Never use ECB mode.&lt;/strong&gt; &lt;strong&gt;ECB&lt;/strong&gt; (Electronic Code Book) encrypts each 16-byte block independently, so identical blocks produce identical ciphertext. It famously leaks patterns in data (look up the “ECB penguin” to see why this matters).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Key size:&lt;/strong&gt; AES-128 (16 bytes) is still considered secure, but AES-256 (32 bytes) is the standard recommendation. Generate keys with a CSPRNG (see below), never derive them from a password with SHA-256.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Practical example: encrypting sensitive fields in a database.&lt;/strong&gt; Say your app stores health records and the &lt;code&gt;diagnosis&lt;/code&gt; column must be encrypted at rest so that even a stolen database dump leaks nothing useful. On write, you generate a fresh 12-byte nonce with &lt;code&gt;randomBytes(12)&lt;/code&gt;, encrypt the plaintext diagnosis with &lt;code&gt;aes-256-gcm&lt;/code&gt; using your data key, and store &lt;code&gt;nonce || auth_tag || ciphertext&lt;/code&gt; together as a single blob in the column. On read, you split the blob back apart and call &lt;code&gt;decipher.setAuthTag(tag)&lt;/code&gt; before decrypting — if anyone has flipped a single byte in the ciphertext (or tried to swap one patient’s record into another), &lt;code&gt;decipher.final()&lt;/code&gt; throws and you reject the read. The encryption key itself lives in your KMS, not in the database, so leaking the database alone is useless to the attacker.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;where-do-encryption-keys-live&quot;&gt;Where Do Encryption Keys Live?&lt;/h2&gt;
&lt;p&gt;Encryption is only as strong as the secrecy of the key. The most common real-world failure isn’t broken crypto — it’s a key checked into a git repo or hardcoded in source code.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Never&lt;/strong&gt; commit keys to source code, &lt;code&gt;.env&lt;/code&gt; files in the repo, or container images.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Development:&lt;/strong&gt; environment variables loaded from a local &lt;code&gt;.env&lt;/code&gt; that’s git-ignored.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Production:&lt;/strong&gt; a dedicated &lt;strong&gt;secrets manager&lt;/strong&gt; or &lt;strong&gt;Key Management Service (KMS)&lt;/strong&gt; — AWS KMS, GCP Cloud KMS, Azure Key Vault, HashiCorp Vault, Doppler. These services hold the key, enforce access control, and log every use. Your application asks the KMS to encrypt or decrypt on its behalf; the raw key material never lives in your application memory.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;rotating-keys&quot;&gt;Rotating Keys&lt;/h3&gt;
&lt;p&gt;Key rotation means replacing an old key with a new one periodically or immediately after a suspected leak. The goal: if a key is ever exposed, the window of damage is bounded.&lt;/p&gt;
&lt;p&gt;The challenge: data encrypted with the old key can’t be decrypted with the new one. The solution is to version your keys and tag your ciphertext with which version encrypted it:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# store with a version prefix&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;v1:3f8a12...:aabbcc...   ← encrypted with key version 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;v2:9d1f44...:112233...   ← encrypted with key version 2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;During a rotation:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Generate key v2. Start encrypting all &lt;strong&gt;new&lt;/strong&gt; data with it.&lt;/li&gt;
&lt;li&gt;On reads, check the version prefix and decrypt with the matching key.&lt;/li&gt;
&lt;li&gt;Lazily re-encrypt old records as they’re accessed — write them back encrypted with v2.&lt;/li&gt;
&lt;li&gt;Once no v1-tagged records remain, retire key v1.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Nonces don’t rotate.&lt;/strong&gt; A nonce is generated fresh for every single encryption operation and stored alongside that one ciphertext forever. You never reuse or “update” a nonce. If you’re thinking about nonce management — don’t. Just always call &lt;code&gt;randomBytes(12)&lt;/code&gt; and you’re done.&lt;/p&gt;
&lt;h3 id=&quot;envelope-encryption&quot;&gt;Envelope Encryption&lt;/h3&gt;
&lt;p&gt;If you encrypted all your records directly with a single master key, rotating that key would mean re-encrypting every record through KMS — slow, expensive, and risky at scale.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Envelope encryption&lt;/strong&gt; solves this with two layers:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Master Key  ← lives in KMS, you never see the raw bytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     ↓  encrypts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; Data Key   ← one per record (or batch), stored alongside the ciphertext&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     ↓  encrypts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; Your data&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The workflow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Ask KMS to generate a &lt;strong&gt;data key&lt;/strong&gt;. KMS returns two things: the plaintext data key, and an encrypted copy of it (the “wrapped key”).&lt;/li&gt;
&lt;li&gt;Encrypt your data locally with the plaintext data key using AES-256-GCM (fast, no KMS call per byte).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Discard&lt;/strong&gt; the plaintext data key from memory immediately.&lt;/li&gt;
&lt;li&gt;Store the wrapped key + nonce + ciphertext together.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To decrypt:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Send the wrapped key to KMS. KMS decrypts it with the master key and returns the plaintext data key.&lt;/li&gt;
&lt;li&gt;Decrypt your data locally.&lt;/li&gt;
&lt;li&gt;Discard the plaintext data key again.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Why this is better than encrypting everything with one key:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The master key never leaves KMS, so it’s never exposed in your app’s memory.&lt;/li&gt;
&lt;li&gt;To rotate the master key, you only re-wrap the small data keys — not the entire dataset. Re-keying a billion records is a billion tiny KMS calls on kilobyte-sized keys, not re-encrypting terabytes of data.&lt;/li&gt;
&lt;li&gt;Different records can have different data keys, so a single compromised key doesn’t expose everything.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AWS S3 server-side encryption, Google Cloud Storage, and most database encryption-at-rest systems all use this pattern under the hood.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;asymmetric-encryption-rsa-and-elliptic-curves&quot;&gt;Asymmetric Encryption: RSA and Elliptic Curves&lt;/h2&gt;
&lt;p&gt;So far everything has been &lt;strong&gt;symmetric&lt;/strong&gt; — the same key encrypts and decrypts. &lt;strong&gt;Asymmetric&lt;/strong&gt; cryptography uses a key pair: a public key and a private key.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Public key&lt;/strong&gt; — safe to share with anyone. Used to encrypt data or verify a signature.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Private key&lt;/strong&gt; — never shared. Used to decrypt data or create a signature.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This solves the key distribution problem: how do you securely send a key to someone you’ve never met? You publish your public key, they encrypt with it, only you can decrypt.&lt;/p&gt;
&lt;p&gt;Asymmetric algorithms are roughly &lt;strong&gt;1000× slower&lt;/strong&gt; than AES, so in practice you never encrypt bulk data with them directly. The standard pattern (&lt;strong&gt;hybrid encryption&lt;/strong&gt;, which is essentially what TLS does on every HTTPS request):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Generate a random AES key (the “session key”).&lt;/li&gt;
&lt;li&gt;Encrypt the data with AES.&lt;/li&gt;
&lt;li&gt;Encrypt the AES key with the recipient’s public &lt;strong&gt;RSA&lt;/strong&gt; (Rivest–Shamir–Adleman) key.&lt;/li&gt;
&lt;li&gt;Send both the encrypted key and the encrypted data.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;ECDSA&lt;/strong&gt; (Elliptic Curve Digital Signature Algorithm) and &lt;strong&gt;Ed25519&lt;/strong&gt;, despite using elliptic curves, are &lt;strong&gt;signature&lt;/strong&gt; algorithms — they cannot encrypt. For elliptic-curve encryption you use &lt;strong&gt;ECDH&lt;/strong&gt; (Elliptic Curve Diffie–Hellman) to derive a shared AES key, then encrypt with AES.&lt;/p&gt;
&lt;p&gt;Where asymmetric crypto shows up for engineers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;JWT with RS256/ES256&lt;/strong&gt;: signing tokens with a private key, verifying with a public key.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SSH keys&lt;/strong&gt;: your &lt;code&gt;~/.ssh/id_ed25519&lt;/code&gt; is a private key; the &lt;code&gt;.pub&lt;/code&gt; file is the public key added to servers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HTTPS/TLS&lt;/strong&gt;: the certificate is a public key. Your browser uses it during the handshake.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;practical-example-github-ssh-authentication&quot;&gt;Practical example: GitHub SSH authentication&lt;/h3&gt;
&lt;p&gt;When you set up &lt;code&gt;git push&lt;/code&gt; over SSH, you run &lt;code&gt;ssh-keygen -t ed25519&lt;/code&gt; once. It produces two files in &lt;code&gt;~/.ssh/&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;id_ed25519&lt;/code&gt; — your &lt;strong&gt;private&lt;/strong&gt; key. Stays on your laptop. Never shared.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;id_ed25519.pub&lt;/code&gt; — your &lt;strong&gt;public&lt;/strong&gt; key. A single line of text starting with &lt;code&gt;ssh-ed25519 …&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You open GitHub → Settings → SSH and GPG keys → New SSH key, and paste the contents of the &lt;code&gt;.pub&lt;/code&gt; file. From now on, every time you &lt;code&gt;git push&lt;/code&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;GitHub’s SSH server sends your machine a random challenge string.&lt;/li&gt;
&lt;li&gt;Your local &lt;code&gt;ssh-agent&lt;/code&gt; signs the challenge with your private key.&lt;/li&gt;
&lt;li&gt;Your machine sends the signature back.&lt;/li&gt;
&lt;li&gt;GitHub verifies the signature using the public key you uploaded.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If the signature checks out, GitHub knows the connection is from someone who holds the matching private key — i.e. you. The private key never leaves your laptop, not even during the handshake. And here’s the magic: if GitHub’s database of public keys leaked tomorrow, the attacker still couldn’t impersonate you, because public keys are useless for &lt;em&gt;creating&lt;/em&gt; signatures. They can only verify them.&lt;/p&gt;
&lt;p&gt;The same pattern powers &lt;code&gt;gh auth&lt;/code&gt; with GPG signing, signed git commits (the green “Verified” badge on github.com), &lt;code&gt;git push&lt;/code&gt; over HTTPS with a personal access token wrapped by a passkey, deploy keys, and CI/CD runners pulling private repos.&lt;/p&gt;
&lt;h3 id=&quot;choosing-a-curve&quot;&gt;Choosing a curve&lt;/h3&gt;
&lt;p&gt;For new asymmetric work, prefer &lt;strong&gt;Ed25519&lt;/strong&gt; (EdDSA) or &lt;strong&gt;ECDSA with P-256&lt;/strong&gt; over RSA. They’re smaller, faster, and more resistant to implementation mistakes. A 256-bit Ed25519 key offers roughly the same security as a 3072-bit RSA key, with much smaller signatures and faster verification.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;secure-random-the-foundation-everything-else-needs&quot;&gt;Secure Random: The Foundation Everything Else Needs&lt;/h2&gt;
&lt;p&gt;Keys, salts, nonces, session tokens, &lt;strong&gt;CSRF&lt;/strong&gt; (Cross-Site Request Forgery) tokens — all require &lt;strong&gt;cryptographically secure pseudorandom numbers (CSPRNG)&lt;/strong&gt;. A CSPRNG draws entropy from the operating system (hardware events, timing jitter, CPU noise) and produces output that is computationally indistinguishable from true randomness.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Go — crypto/rand, not math/rand&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;crypto/rand&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;token &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; make&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;([]&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;byte&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;32&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; _, err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; rand.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Read&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(token); err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    panic&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(err) &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// entropy source unavailable — refuse to continue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Node.js — node:crypto, not Math.random()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; { randomBytes } &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;node:crypto&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; token&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; randomBytes&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;32&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Buffer of 32 random bytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; tokenHex&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; token.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;toString&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;hex&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// 64-char hex string&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Practical example: password reset links.&lt;/strong&gt; When a user clicks “forgot password,” your server generates 32 bytes from &lt;code&gt;randomBytes(32)&lt;/code&gt;, stores its SHA-256 in the database alongside the user ID and a 15-minute expiry, and emails the user a link like &lt;code&gt;https://app.com/reset?token=&amp;#x3C;hex&gt;&lt;/code&gt;. When the link is clicked, you SHA-256 the supplied token, look up the record, check the expiry, and let the user choose a new password. Because the token has 256 bits of entropy, an attacker can’t guess valid reset tokens by trying random URLs. The same primitive powers session cookies, API keys returned on signup, OAuth &lt;code&gt;state&lt;/code&gt; parameters, and CSRF form tokens — anywhere you need an unguessable identifier.&lt;/p&gt;
&lt;h3 id=&quot;what-is-entropy&quot;&gt;What is entropy?&lt;/h3&gt;
&lt;p&gt;Entropy is a measure of unpredictability. A coin flip has 1 bit of entropy — two possibilities. A 32-byte random token has 256 bits of entropy — there are 2²⁵⁶ possible values. At a billion guesses per second, exhausting that space would take longer than the age of the universe.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Math.random()&lt;/code&gt; and &lt;code&gt;rand.Intn()&lt;/code&gt; typically have 32–64 bits of internal state, seeded from a predictable source like the system clock or process ID. An attacker who knows roughly when your server started can narrow the seed space to a few million values and brute-force a session token in seconds.&lt;/p&gt;
&lt;p&gt;A CSPRNG seeds itself from sources that are genuinely unpredictable to an outside observer — hardware interrupts, CPU timing jitter, OS entropy pools. This is what &lt;code&gt;crypto/rand&lt;/code&gt; and &lt;code&gt;node:crypto&lt;/code&gt; use under the hood.&lt;/p&gt;
&lt;h3 id=&quot;how-many-bytes-do-you-need&quot;&gt;How many bytes do you need?&lt;/h3&gt;








































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Use case&lt;/th&gt;&lt;th&gt;Bytes&lt;/th&gt;&lt;th&gt;Why&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Session token / API key&lt;/td&gt;&lt;td&gt;32&lt;/td&gt;&lt;td&gt;256-bit security margin&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CSRF token&lt;/td&gt;&lt;td&gt;32&lt;/td&gt;&lt;td&gt;Same&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;AES-256 encryption key&lt;/td&gt;&lt;td&gt;32&lt;/td&gt;&lt;td&gt;Exactly fills the key size&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;AES-GCM nonce&lt;/td&gt;&lt;td&gt;12&lt;/td&gt;&lt;td&gt;Standard for GCM mode&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;KDF salt&lt;/td&gt;&lt;td&gt;16&lt;/td&gt;&lt;td&gt;128 bits is more than sufficient&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Password reset token&lt;/td&gt;&lt;td&gt;32&lt;/td&gt;&lt;td&gt;Short-lived, but still needs full entropy&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;More bytes is rarely better — 32 bytes is already far beyond what anyone can brute-force. The risk is always the generator, not the length.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;when-youd-rather-not-choose-high-level-libraries&quot;&gt;When You’d Rather Not Choose: High-Level Libraries&lt;/h2&gt;
&lt;p&gt;The standard &lt;code&gt;crypto&lt;/code&gt; modules expose primitives — building blocks. Picking and combining them correctly is where most bugs live. If you’d rather not, a few well-regarded “use this and you’ll probably be fine” options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;libsodium&lt;/strong&gt; (&lt;code&gt;crypto_secretbox&lt;/code&gt;, &lt;code&gt;crypto_box&lt;/code&gt;) — bindings exist for every language. Picks safe defaults: XChaCha20-Poly1305 for symmetric, X25519 for key exchange, Ed25519 for signing. You don’t choose the nonce size or the cipher mode — there’s only one of each, and it’s a good one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;age&lt;/strong&gt; (&lt;code&gt;age-encryption.org&lt;/code&gt;) — file-encryption tool and library. Simple key format, small surface area, hard to misuse.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Web Crypto API&lt;/strong&gt; (&lt;code&gt;crypto.subtle&lt;/code&gt; in browsers and Node.js) — the cross-platform standard for client-side JavaScript. Async by design.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Reach for these when you don’t have a specific reason to use the lower-level primitives.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;decision-tree-what-to-use-when&quot;&gt;Decision Tree: What to Use When&lt;/h2&gt;


















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Scenario&lt;/th&gt;&lt;th&gt;Primitive&lt;/th&gt;&lt;th&gt;Algorithm&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Store a user password&lt;/td&gt;&lt;td&gt;KDF&lt;/td&gt;&lt;td&gt;Argon2id or bcrypt (cost ≥ 12)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Verify a file download&lt;/td&gt;&lt;td&gt;Hash&lt;/td&gt;&lt;td&gt;SHA-256&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Sign an API webhook payload&lt;/td&gt;&lt;td&gt;HMAC&lt;/td&gt;&lt;td&gt;HMAC-SHA256&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Encrypt data at rest&lt;/td&gt;&lt;td&gt;Symmetric&lt;/td&gt;&lt;td&gt;AES-256-GCM&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Sign a JWT&lt;/td&gt;&lt;td&gt;HMAC or asymmetric&lt;/td&gt;&lt;td&gt;HS256 (HMAC) or ES256 (ECDSA)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Generate a session token&lt;/td&gt;&lt;td&gt;Secure random&lt;/td&gt;&lt;td&gt;&lt;code&gt;crypto/rand&lt;/code&gt;, &lt;code&gt;randomBytes&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Derive a key from a password&lt;/td&gt;&lt;td&gt;KDF&lt;/td&gt;&lt;td&gt;Argon2id or PBKDF2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Exchange keys with a stranger&lt;/td&gt;&lt;td&gt;Asymmetric&lt;/td&gt;&lt;td&gt;ECDH (key exchange)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&quot;common-mistakes-checklist&quot;&gt;Common Mistakes Checklist&lt;/h2&gt;
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Using &lt;code&gt;MD5&lt;/code&gt; or &lt;code&gt;SHA-1&lt;/code&gt; for anything security-related&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Hashing passwords with &lt;code&gt;SHA-256&lt;/code&gt; instead of a KDF&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Reusing a nonce when encrypting with AES-GCM&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Using &lt;code&gt;Math.random()&lt;/code&gt; / &lt;code&gt;rand.Intn()&lt;/code&gt; for tokens or keys&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Comparing MACs with &lt;code&gt;===&lt;/code&gt; instead of a constant-time function&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Using AES in ECB mode&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Storing encryption keys next to the encrypted data&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Committing keys or secrets to source control&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Forgetting bcrypt silently truncates at 72 bytes&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Rolling your own crypto algorithm (don’t — ever)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The last point is worth emphasising: &lt;strong&gt;don’t invent new algorithms&lt;/strong&gt;. Every primitive described in this post has been analysed by thousands of cryptographers for decades. The crypto module exists so you never have to think about the mathematics — your only job is to pick the right primitive and use it correctly.&lt;/p&gt;</content:encoded></item><item><title>Vectors and Matrices: The Language Neural Networks Speak</title><link>https://abhimanyunagurkar.com/blog/math-for-ml-1-vectors-and-matrices/</link><guid isPermaLink="true">https://abhimanyunagurkar.com/blog/math-for-ml-1-vectors-and-matrices/</guid><description>A ground-up introduction to vectors, matrices, dot products, and matrix multiplication — the operations every neural network is built from.</description><pubDate>Sun, 10 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Every neural network, no matter how large, is doing one thing repeatedly: multiplying matrices and adding vectors. GPT-4 with its hundreds of billions of parameters is, at its core, a long chain of these operations. Before you can understand attention, backpropagation, or transformers, you need to be fluent in the arithmetic they’re written in.&lt;/p&gt;
&lt;p&gt;This post builds that fluency from scratch, with worked examples at every step.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;scalars-vectors-and-matrices&quot;&gt;Scalars, Vectors, and Matrices&lt;/h2&gt;
&lt;p&gt;A &lt;strong&gt;scalar&lt;/strong&gt; is a single number. Temperature (22°C), price ($9.99), age (31) — all scalars.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;vector&lt;/strong&gt; is an ordered list of numbers. It has both a magnitude (how big) and a direction (which way).&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;v = [3, 2]       (a 2D vector)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;w = [1, 0, -4]   (a 3D vector)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Geometrically, &lt;code&gt;v = [3, 2]&lt;/code&gt; means “go 3 units right and 2 units up.” Vectors live in space.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;matrix&lt;/strong&gt; is a rectangular grid of numbers, arranged in rows and columns.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;A = [[2, 0],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     [1, 3]]    (a 2×2 matrix — 2 rows, 2 columns)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We say matrix &lt;code&gt;A&lt;/code&gt; has shape &lt;code&gt;(2, 2)&lt;/code&gt;. A matrix with &lt;code&gt;m&lt;/code&gt; rows and &lt;code&gt;n&lt;/code&gt; columns has shape &lt;code&gt;(m, n)&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;vector-operations&quot;&gt;Vector Operations&lt;/h2&gt;
&lt;h3 id=&quot;addition&quot;&gt;Addition&lt;/h3&gt;
&lt;p&gt;Add vectors component by component. Both vectors must have the same length.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;a = [1, 2, 3]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;b = [4, 5, 6]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;a + b = [1+4, 2+5, 3+6] = [5, 7, 9]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Geometrically: place vector &lt;code&gt;b&lt;/code&gt; at the tip of vector &lt;code&gt;a&lt;/code&gt;. The result points from the origin to where &lt;code&gt;b&lt;/code&gt; ends.&lt;/p&gt;
&lt;h3 id=&quot;scalar-multiplication&quot;&gt;Scalar Multiplication&lt;/h3&gt;
&lt;p&gt;Multiply every component by the same number.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;a = [1, 2, 3]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;3 * a = [3, 6, 9]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This stretches (or shrinks, or flips) the vector without changing its direction.&lt;/p&gt;
&lt;h3 id=&quot;the-dot-product&quot;&gt;The Dot Product&lt;/h3&gt;
&lt;p&gt;This one is crucial. The dot product of two vectors is a single number (a scalar):&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;a · b = a[0]*b[0] + a[1]*b[1] + ... + a[n]*b[n]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Worked example:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;a = [1, 2, 3]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;b = [4, 5, 6]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;a · b = (1×4) + (2×5) + (3×6)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      = 4 + 10 + 18&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      = 32&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The dot product measures how much two vectors point in the same direction. If two vectors are perpendicular, their dot product is 0. If they point in the same direction, it’s large and positive. This property becomes the foundation of the attention mechanism in transformers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Geometric interpretation:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;a · b = |a| × |b| × cos(θ)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where &lt;code&gt;|a|&lt;/code&gt; is the &lt;strong&gt;length&lt;/strong&gt; (or magnitude) of vector &lt;code&gt;a&lt;/code&gt; — computed as &lt;code&gt;sqrt(a[0]² + a[1]² + ...)&lt;/code&gt;. &lt;code&gt;θ&lt;/code&gt; is the angle between the two vectors. &lt;code&gt;cos(0°) = 1&lt;/code&gt; (same direction), &lt;code&gt;cos(90°) = 0&lt;/code&gt; (perpendicular), &lt;code&gt;cos(180°) = -1&lt;/code&gt; (opposite).&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;matrices&quot;&gt;Matrices&lt;/h2&gt;
&lt;h3 id=&quot;what-a-matrix-represents&quot;&gt;What a Matrix Represents&lt;/h3&gt;
&lt;p&gt;A matrix can represent many things: a dataset (rows = examples, columns = features), a transformation of space, or — most importantly for neural networks — the &lt;strong&gt;weights&lt;/strong&gt; connecting one layer to the next.&lt;/p&gt;
&lt;h3 id=&quot;matrix-multiplication&quot;&gt;Matrix Multiplication&lt;/h3&gt;
&lt;p&gt;This is the core operation. To multiply matrix &lt;code&gt;A&lt;/code&gt; (shape &lt;code&gt;m×n&lt;/code&gt;) by matrix &lt;code&gt;B&lt;/code&gt; (shape &lt;code&gt;n×p&lt;/code&gt;), the output &lt;code&gt;C&lt;/code&gt; has shape &lt;code&gt;m×p&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The rule: entry &lt;code&gt;C[i][j]&lt;/code&gt; is the dot product of row &lt;code&gt;i&lt;/code&gt; of &lt;code&gt;A&lt;/code&gt; with column &lt;code&gt;j&lt;/code&gt; of &lt;code&gt;B&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Worked example (2×2 × 2×2):&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;A = [[1, 2],    B = [[5, 6],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     [3, 4]]         [7, 8]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;C[0][0] = row 0 of A · col 0 of B = [1,2]·[5,7] = (1×5)+(2×7) = 19&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;C[0][1] = row 0 of A · col 1 of B = [1,2]·[6,8] = (1×6)+(2×8) = 22&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;C[1][0] = row 1 of A · col 0 of B = [3,4]·[5,7] = (3×5)+(4×7) = 43&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;C[1][1] = row 1 of A · col 1 of B = [3,4]·[6,8] = (3×6)+(4×8) = 50&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;C = [[19, 22],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     [43, 50]]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Worked example (2×3 × 3×2 → 2×2):&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;A = [[1, 0, 2],     B = [[1, 2],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     [3, 1, 0]]          [0, 1],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                          [4, 0]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;C[0][0] = [1,0,2]·[1,0,4] = 1+0+8 = 9&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;C[0][1] = [1,0,2]·[2,1,0] = 2+0+0 = 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;C[1][0] = [3,1,0]·[1,0,4] = 3+0+0 = 3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;C[1][1] = [3,1,0]·[2,1,0] = 6+1+0 = 7&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;C = [[9, 2],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     [3, 7]]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; matrix multiplication is not commutative. &lt;code&gt;A × B ≠ B × A&lt;/code&gt; in general. The inner dimensions must match: &lt;code&gt;(m×n) × (n×p)&lt;/code&gt; works; &lt;code&gt;(m×n) × (p×n)&lt;/code&gt; does not (unless &lt;code&gt;p = m&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id=&quot;the-transpose&quot;&gt;The Transpose&lt;/h3&gt;
&lt;p&gt;The transpose of a matrix, written &lt;code&gt;Aᵀ&lt;/code&gt;, flips rows and columns.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;A = [[1, 2, 3],       Aᵀ = [[1, 4],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     [4, 5, 6]]              [2, 5],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                              [3, 6]]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If &lt;code&gt;A&lt;/code&gt; has shape &lt;code&gt;(m, n)&lt;/code&gt;, then &lt;code&gt;Aᵀ&lt;/code&gt; has shape &lt;code&gt;(n, m)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The transpose appears constantly in neural networks, particularly in the attention formula &lt;code&gt;QKᵀ&lt;/code&gt; (which you’ll see in post 7).&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;why-shape-tracking-matters&quot;&gt;Why Shape Tracking Matters&lt;/h2&gt;
&lt;p&gt;In code, shape errors are the most common bug when building neural networks. Getting comfortable with shapes now prevents a lot of pain later.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; numpy &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; np&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;A &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; np.array([[&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;              [&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]])   &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# shape (2, 3)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;B &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; np.array([[&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;7&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;8&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;              [&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;9&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;              [&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;11&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;12&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]])    &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# shape (3, 2)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;C &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; A &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; B                   &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# shape (2, 2) — inner dims match (3 == 3)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(C)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# [[58  64]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;#  [139 154]]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;@&lt;/code&gt; operator in Python is matrix multiplication (same as &lt;code&gt;np.matmul&lt;/code&gt;). If you try to multiply shapes that don’t align, NumPy will raise an error immediately.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;a-neural-network-layer-in-one-line&quot;&gt;A Neural Network Layer in One Line&lt;/h2&gt;
&lt;p&gt;Here’s the payoff. A single layer in a neural network computes:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;output = activation(W @ input + b)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;W&lt;/code&gt; is the &lt;strong&gt;weight matrix&lt;/strong&gt; — shape &lt;code&gt;(output_size, input_size)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;input&lt;/code&gt; is the input vector — shape &lt;code&gt;(input_size,)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;b&lt;/code&gt; is the &lt;strong&gt;bias vector&lt;/strong&gt; — shape &lt;code&gt;(output_size,)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;activation&lt;/code&gt; is a nonlinear function (ReLU, sigmoid, etc.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Worked example:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;W = [[0.5, -0.2],    # shape (3, 2)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     [0.1,  0.8],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     [-0.3, 0.4]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;input = [2.0, 1.0]   # shape (2,)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;b     = [0.1, -0.1, 0.2]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;z = W @ input + b&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  = [0.5*2 + (-0.2)*1 + 0.1,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     0.1*2 +   0.8*1 + (-0.1),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     -0.3*2 + 0.4*1 + 0.2]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  = [0.9, 0.9, 0.0]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s a 3-neuron layer processing a 2-dimensional input. The matrix &lt;code&gt;W&lt;/code&gt; has 3×2 = 6 learnable weights — the numbers that training will adjust to minimise the loss.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;key-takeaways&quot;&gt;Key Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;vector&lt;/strong&gt; is an ordered list of numbers with magnitude and direction.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;dot product&lt;/strong&gt; &lt;code&gt;a · b&lt;/code&gt; measures similarity between two vectors — large when they point the same way, zero when perpendicular.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;matrix&lt;/strong&gt; is a grid of numbers that can represent a transformation, a dataset, or a set of weights.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Matrix multiplication&lt;/strong&gt; chains transformations together. Shape &lt;code&gt;(m×n) × (n×p) → (m×p)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;One neural network layer = &lt;code&gt;W @ x + b&lt;/code&gt; followed by an activation function.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Everything in the rest of this series builds directly on these operations. Next: the calculus that teaches a network to improve.&lt;/p&gt;</content:encoded></item><item><title>Derivatives and Gradients: Teaching Machines to Improve</title><link>https://abhimanyunagurkar.com/blog/math-for-ml-2-derivatives-and-gradients/</link><guid isPermaLink="true">https://abhimanyunagurkar.com/blog/math-for-ml-2-derivatives-and-gradients/</guid><description>Derivatives, the chain rule, partial derivatives, the gradient, and gradient descent — the calculus that drives every step of neural network learning.</description><pubDate>Sun, 10 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A neural network learns by making a mistake and then figuring out which weights caused it — and by how much. The tool that makes this possible is calculus: specifically, derivatives and gradients.&lt;/p&gt;
&lt;p&gt;If you learned derivatives in school and then forgot them, this post will rebuild exactly what you need. If you’ve never seen them, this covers everything from the ground up.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;what-is-a-derivative&quot;&gt;What Is a Derivative?&lt;/h2&gt;
&lt;p&gt;A derivative measures how much a function’s output changes when you nudge its input.&lt;/p&gt;
&lt;p&gt;Formally, the derivative of &lt;code&gt;f(x)&lt;/code&gt; at a point &lt;code&gt;x₀&lt;/code&gt; is:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;f&apos;(x₀) = lim(h→0) [f(x₀ + h) - f(x₀)] / h&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The notation &lt;code&gt;lim(h→0)&lt;/code&gt; means “the value this expression approaches as &lt;code&gt;h&lt;/code&gt; gets vanishingly small.” The whole formula is asking: if I move &lt;code&gt;x&lt;/code&gt; by a tiny amount &lt;code&gt;h&lt;/code&gt;, how much does &lt;code&gt;f(x)&lt;/code&gt; change per unit of that movement? The answer is the slope of the function at that point.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example: f(x) = x²&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;f(x₀ + h) - f(x₀)   (x₀+h)² - x₀²   x₀² + 2x₀h + h² - x₀²&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;——————————————————— = ——————————————— = ——————————————————————&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         h                  h                      h&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                                       = 2x₀ + h&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As &lt;code&gt;h → 0&lt;/code&gt;, this becomes &lt;code&gt;2x₀&lt;/code&gt;. So the derivative of &lt;code&gt;x²&lt;/code&gt; is &lt;code&gt;2x&lt;/code&gt;. At &lt;code&gt;x = 3&lt;/code&gt;, the slope is 6.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;derivative-rules&quot;&gt;Derivative Rules&lt;/h2&gt;
&lt;p&gt;You rarely need the limit definition in practice. These rules cover almost everything:&lt;/p&gt;

































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Function&lt;/th&gt;&lt;th&gt;Derivative&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;xⁿ&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;n·xⁿ⁻¹&lt;/code&gt; (power rule)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;eˣ&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;eˣ&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;ln(x)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;1/x&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;c&lt;/code&gt; (constant)&lt;/td&gt;&lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;c·f(x)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;c·f&apos;(x)&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;f(x) + g(x)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;f&apos;(x) + g&apos;(x)&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;The chain rule&lt;/strong&gt; is the most important one for neural networks:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;If y = f(g(x)), then dy/dx = f&apos;(g(x)) · g&apos;(x)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In plain words: the derivative of a composition equals the outer derivative times the inner derivative.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;y = (3x + 1)²&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Let g(x) = 3x + 1   →  g&apos;(x) = 3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Let f(u) = u²        →  f&apos;(u) = 2u&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;dy/dx = f&apos;(g(x)) · g&apos;(x) = 2(3x+1) · 3 = 6(3x+1)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At &lt;code&gt;x = 1&lt;/code&gt;: &lt;code&gt;dy/dx = 6(3+1) = 24&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A neural network is a long composition of functions. The chain rule is how gradients flow backward through all of them — which is exactly what backpropagation does (covered in post 5).&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;partial-derivatives&quot;&gt;Partial Derivatives&lt;/h2&gt;
&lt;p&gt;Neural networks have millions of parameters, not one. A function of multiple variables uses &lt;strong&gt;partial derivatives&lt;/strong&gt;: the derivative with respect to one variable, treating all others as constants.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Notation:&lt;/strong&gt; &lt;code&gt;∂f/∂x&lt;/code&gt; means “the partial derivative of f with respect to x.”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example: f(x, y) = x² + 3xy + y²&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂f/∂x = 2x + 3y      (treat y as a constant, differentiate by x)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂f/∂y = 3x + 2y      (treat x as a constant, differentiate by y)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At &lt;code&gt;(x=2, y=1)&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂f/∂x = 2(2) + 3(1) = 7&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂f/∂y = 3(2) + 2(1) = 8&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This tells us: at the point &lt;code&gt;(2, 1)&lt;/code&gt;, moving slightly in the &lt;code&gt;x&lt;/code&gt; direction increases &lt;code&gt;f&lt;/code&gt; by about 7× that movement; moving slightly in the &lt;code&gt;y&lt;/code&gt; direction increases &lt;code&gt;f&lt;/code&gt; by about 8×.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-gradient&quot;&gt;The Gradient&lt;/h2&gt;
&lt;p&gt;The &lt;strong&gt;gradient&lt;/strong&gt; of a function is the vector of all its partial derivatives:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∇f(x, y) = [∂f/∂x, ∂f/∂y]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For a function of &lt;code&gt;n&lt;/code&gt; variables, the gradient is an &lt;code&gt;n&lt;/code&gt;-dimensional vector.&lt;/p&gt;
&lt;p&gt;The gradient always points in the direction of &lt;strong&gt;steepest increase&lt;/strong&gt;. If you’re standing on a hillside, the gradient points uphill. Its negative, &lt;code&gt;-∇f&lt;/code&gt;, points downhill — toward the minimum.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For the example above at (2, 1):&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∇f(2, 1) = [7, 8]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The function increases fastest in the direction &lt;code&gt;[7, 8]&lt;/code&gt;. To find a minimum, we move in the direction &lt;code&gt;[-7, -8]&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;gradient-descent&quot;&gt;Gradient Descent&lt;/h2&gt;
&lt;p&gt;Training a neural network means minimising a &lt;strong&gt;loss function&lt;/strong&gt; &lt;code&gt;L(w)&lt;/code&gt;, where &lt;code&gt;w&lt;/code&gt; represents all the weights. The loss measures how wrong the network’s predictions are.&lt;/p&gt;
&lt;p&gt;Gradient descent does this iteratively:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Compute the gradient &lt;code&gt;∇L(w)&lt;/code&gt; — which direction does the loss increase fastest?&lt;/li&gt;
&lt;li&gt;Take a small step in the opposite direction (downhill).&lt;/li&gt;
&lt;li&gt;Repeat.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The update rule is:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;w ← w - η · ∇L(w)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where &lt;code&gt;η&lt;/code&gt; (eta) is the &lt;strong&gt;learning rate&lt;/strong&gt; — a small positive number like &lt;code&gt;0.001&lt;/code&gt; or &lt;code&gt;0.01&lt;/code&gt; that controls how large each step is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why not take huge steps?&lt;/strong&gt; If &lt;code&gt;η&lt;/code&gt; is too large, you overshoot the minimum and the loss oscillates or diverges. Too small, and training takes forever. Finding a good learning rate is one of the main practical challenges in training neural networks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Worked example:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Suppose the loss is &lt;code&gt;L(w) = (w - 3)²&lt;/code&gt; (a simple parabola with minimum at &lt;code&gt;w = 3&lt;/code&gt;). Start at &lt;code&gt;w = 0&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;L&apos;(w) = 2(w - 3)     (derivative of the loss)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;η = 0.3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Step 1: w = 0   L&apos;(0) = 2(0-3) = -6   w ← 0 - 0.3×(-6) = 1.8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Step 2: w = 1.8 L&apos;(1.8) = 2(1.8-3) = -2.4  w ← 1.8 - 0.3×(-2.4) = 2.52&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Step 3: w = 2.52  L&apos;(2.52) = -0.96   w ← 2.52 + 0.288 = 2.808&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Step 4: w = 2.808 → ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each step gets closer to &lt;code&gt;w = 3&lt;/code&gt;. Gradient descent is working.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-loss-surface&quot;&gt;The Loss Surface&lt;/h2&gt;
&lt;p&gt;In a real neural network, &lt;code&gt;L(w)&lt;/code&gt; is a function of millions of weights — the “loss surface” is a high-dimensional landscape. We can’t visualise it, but the mathematics is identical: compute the gradient, step downhill, repeat.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; numpy &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; np&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# simple quadratic loss: L(w) = (w - 3)^2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; loss&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(w):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (w &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; grad_loss&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(w):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (w &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;w &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 0.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;lr &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 0.3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; step &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    g &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; grad_loss(w)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    w &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; w &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; lr &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; g&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;step &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;step&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:2d&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;: w=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;w&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:.4f&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;, L=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;loss(w)&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:.4f&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output converges to &lt;code&gt;w ≈ 3.0&lt;/code&gt; within a handful of steps.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;why-the-chain-rule-is-central&quot;&gt;Why the Chain Rule Is Central&lt;/h2&gt;
&lt;p&gt;In a neural network, the weights &lt;code&gt;w&lt;/code&gt; produce hidden activations, which produce the output &lt;code&gt;ŷ&lt;/code&gt;, which determines the loss &lt;code&gt;L&lt;/code&gt;. This is a chain of compositions:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;w  →  hidden  →  ŷ  →  L&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To compute &lt;code&gt;∂L/∂w&lt;/code&gt;, you apply the chain rule repeatedly:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂L/∂w = ∂L/∂ŷ · ∂ŷ/∂z · ∂z/∂w&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the mathematical heart of backpropagation. Post 5 works through this in full detail.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;key-takeaways&quot;&gt;Key Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;derivative&lt;/strong&gt; &lt;code&gt;f&apos;(x)&lt;/code&gt; measures the slope of &lt;code&gt;f&lt;/code&gt; at &lt;code&gt;x&lt;/code&gt; — how much the output changes per unit change in input.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;chain rule&lt;/strong&gt; handles compositions: &lt;code&gt;d/dx f(g(x)) = f&apos;(g(x)) · g&apos;(x)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;partial derivative&lt;/strong&gt; &lt;code&gt;∂f/∂x&lt;/code&gt; treats all other variables as constants.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;gradient&lt;/strong&gt; &lt;code&gt;∇f&lt;/code&gt; is the vector of all partial derivatives. It points in the direction of steepest increase.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gradient descent&lt;/strong&gt; moves weights in the direction &lt;code&gt;-∇L&lt;/code&gt;, reducing the loss one step at a time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next up: probability and the Gaussian — the mathematical language that neural networks use to express uncertainty and produce predictions.&lt;/p&gt;</content:encoded></item><item><title>Probability and the Gaussian: How Neural Networks Express Uncertainty</title><link>https://abhimanyunagurkar.com/blog/math-for-ml-3-probability-and-gaussian/</link><guid isPermaLink="true">https://abhimanyunagurkar.com/blog/math-for-ml-3-probability-and-gaussian/</guid><description>Probability distributions, the Gaussian, softmax, and cross-entropy loss — the tools neural networks use to express uncertainty and produce predictions.</description><pubDate>Sun, 10 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When a language model says “the next word is probably ‘cat’”, it is producing a probability distribution over its entire vocabulary. When a classifier is 94% confident an image is a dog, that confidence is a number from probability theory. Understanding how neural networks reason about uncertainty requires understanding a handful of core probability concepts.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;probability-basics&quot;&gt;Probability Basics&lt;/h2&gt;
&lt;p&gt;A &lt;strong&gt;probability&lt;/strong&gt; is a number between 0 and 1 that expresses how likely an event is.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;P(event) = 0&lt;/code&gt; means impossible.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;P(event) = 1&lt;/code&gt; means certain.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;P(heads on a fair coin) = 0.5&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For a set of mutually exclusive outcomes that cover all possibilities, probabilities must sum to 1:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;P(heads) + P(tails) = 0.5 + 0.5 = 1.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This constraint — probabilities summing to 1 — is something we’ll enforce explicitly with softmax.&lt;/p&gt;
&lt;h3 id=&quot;expected-value&quot;&gt;Expected Value&lt;/h3&gt;
&lt;p&gt;The expected value &lt;code&gt;E[X]&lt;/code&gt; is the probability-weighted average of all possible outcomes:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;E[X] = Σ x · P(X = x)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; Roll a fair six-sided die. What’s the expected value?&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;E[X] = 1×(1/6) + 2×(1/6) + 3×(1/6) + 4×(1/6) + 5×(1/6) + 6×(1/6)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     = (1+2+3+4+5+6)/6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     = 21/6 = 3.5&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You’ll never actually roll 3.5, but on average over many rolls, this is what you expect.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;probability-distributions&quot;&gt;Probability Distributions&lt;/h2&gt;
&lt;p&gt;A &lt;strong&gt;probability distribution&lt;/strong&gt; describes how probability is spread across possible values of a random variable.&lt;/p&gt;
&lt;p&gt;For a &lt;strong&gt;discrete&lt;/strong&gt; distribution (finite outcomes), we list each outcome and its probability.&lt;/p&gt;
&lt;p&gt;For a &lt;strong&gt;continuous&lt;/strong&gt; distribution (infinite outcomes), we use a &lt;strong&gt;probability density function (PDF)&lt;/strong&gt;: a curve where the area under the curve equals 1, and the area between two values &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; gives &lt;code&gt;P(a ≤ X ≤ b)&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-gaussian-distribution&quot;&gt;The Gaussian Distribution&lt;/h2&gt;
&lt;p&gt;The most important distribution in mathematics and statistics. Also called the &lt;strong&gt;normal distribution&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Its PDF is:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;f(x) = (1 / σ√(2π)) · exp(-(x - μ)² / (2σ²))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two parameters control it completely:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;μ&lt;/code&gt; (mu) — the &lt;strong&gt;mean&lt;/strong&gt;, where the peak sits.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;σ&lt;/code&gt; (sigma) — the &lt;strong&gt;standard deviation&lt;/strong&gt;, how spread out the distribution is. &lt;code&gt;σ²&lt;/code&gt; is the variance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The bell curve is symmetric around &lt;code&gt;μ&lt;/code&gt;. About 68% of the probability mass falls within one standard deviation of the mean (&lt;code&gt;μ ± σ&lt;/code&gt;). About 95% falls within &lt;code&gt;μ ± 2σ&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;why-the-gaussian-appears-everywhere&quot;&gt;Why the Gaussian Appears Everywhere&lt;/h3&gt;
&lt;p&gt;The &lt;strong&gt;Central Limit Theorem&lt;/strong&gt; says: the sum of many independent random variables, regardless of their individual distributions, tends toward a Gaussian. Measurement errors, natural variation in populations, noise in signals — all of these arise from the sum of many small independent effects, so they all look Gaussian.&lt;/p&gt;
&lt;p&gt;In neural networks, the Gaussian appears in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Weight initialisation&lt;/strong&gt; — weights are often initialised by sampling from &lt;code&gt;N(0, σ²)&lt;/code&gt;, which is shorthand for “a normal distribution with mean 0 and variance σ²”.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Noise&lt;/strong&gt; — dropout and other regularisation techniques add controlled randomness.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gaussian processes&lt;/strong&gt; — probabilistic models closely related to neural networks.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;softmax-turning-numbers-into-probabilities&quot;&gt;Softmax: Turning Numbers Into Probabilities&lt;/h2&gt;
&lt;p&gt;A neural network’s output layer for classification typically produces raw scores called &lt;strong&gt;logits&lt;/strong&gt; — one per class, any real value, not constrained to sum to 1. Softmax converts these into a proper probability distribution.&lt;/p&gt;
&lt;p&gt;For a vector of logits &lt;code&gt;z = [z₁, z₂, ..., zₙ]&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;softmax(z)ᵢ = e^zᵢ / Σⱼ e^zⱼ&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each output is always between 0 and 1, and they sum to exactly 1.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Worked example:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;z = [2.0, 1.0, 0.1]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;e^2.0 = 7.389&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;e^1.0 = 2.718&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;e^0.1 = 1.105&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sum   = 11.212&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;softmax = [7.389/11.212, 2.718/11.212, 1.105/11.212]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        = [0.659, 0.242, 0.099]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Check: 0.659 + 0.242 + 0.099 = 1.0  ✓&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The class with logit 2.0 gets about 66% of the probability. The exponential function amplifies differences: adding 1 to a logit multiplies its (unnormalised) weight by &lt;code&gt;e ≈ 2.72&lt;/code&gt;, so small changes in logits become large probability gaps.&lt;/p&gt;
&lt;h3 id=&quot;the-temperature-parameter&quot;&gt;The Temperature Parameter&lt;/h3&gt;
&lt;p&gt;In language models, you’ll see softmax with a &lt;strong&gt;temperature&lt;/strong&gt; &lt;code&gt;T&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;softmax(z/T)ᵢ = e^(zᵢ/T) / Σⱼ e^(zⱼ/T)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;T = 1.0&lt;/code&gt; — standard softmax.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;T &amp;#x3C; 1.0&lt;/code&gt; — sharper distribution (more confident, more predictable outputs).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;T &gt; 1.0&lt;/code&gt; — flatter distribution (more random, more creative outputs).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When you use “temperature” in a language model API, this is the parameter you’re controlling.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;cross-entropy-loss&quot;&gt;Cross-Entropy Loss&lt;/h2&gt;
&lt;p&gt;How do you measure how wrong a predicted probability distribution is? With cross-entropy.&lt;/p&gt;
&lt;p&gt;For a single example with true label &lt;code&gt;y&lt;/code&gt; (one-hot encoded — a vector of zeros with a single 1 at the correct class) and predicted probabilities &lt;code&gt;ŷ&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;L = -Σᵢ yᵢ · log(ŷᵢ)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because &lt;code&gt;y&lt;/code&gt; is one-hot (only one class is correct), this simplifies to:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;L = -log(ŷ_correct)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where &lt;code&gt;ŷ_correct&lt;/code&gt; is the predicted probability assigned to the true class.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Worked example:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Throughout this series, &lt;code&gt;log&lt;/code&gt; means the &lt;strong&gt;natural logarithm&lt;/strong&gt; (base &lt;code&gt;e&lt;/code&gt;), which is the standard in machine learning.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;True class: cat (index 1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Predictions: [0.10, 0.70, 0.20]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;L = -log(0.70) ≈ 0.357&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the model had been confident and wrong:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Predictions: [0.05, 0.10, 0.85]   (cat is index 1, model predicts index 2)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;L = -log(0.10) = 2.303   ← much higher loss&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cross-entropy loss grows sharply as the predicted probability of the correct class approaches zero. This is what motivates the model to assign high probability to correct classes.&lt;/p&gt;
&lt;h3 id=&quot;why-log&quot;&gt;Why log?&lt;/h3&gt;
&lt;p&gt;The logarithm has a key property: &lt;code&gt;log(1) = 0&lt;/code&gt; (perfect prediction → zero loss), and &lt;code&gt;log(x) → -∞&lt;/code&gt; as &lt;code&gt;x → 0&lt;/code&gt; (confident wrong prediction → infinite loss). It also has nice mathematical properties that make the gradients clean.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;putting-it-together-the-classification-pipeline&quot;&gt;Putting It Together: The Classification Pipeline&lt;/h2&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Input → Neural Network → Logits → Softmax → Probabilities → Cross-Entropy Loss&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step by step for a 3-class classifier:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;input = [0.5, 1.2]              # some input features&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;W = [[0.3, -0.1],               # weight matrix (3×2)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     [0.2,  0.4],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     [-0.5, 0.7]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;b = [0.1, 0.0, -0.2]           # biases&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;logits = W @ input + b&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       = [0.3*0.5 + (-0.1)*1.2 + 0.1,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          0.2*0.5 + 0.4*1.2 + 0.0,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          -0.5*0.5 + 0.7*1.2 + (-0.2)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       = [0.13, 0.58, 0.39]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# softmax:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;e^0.13 ≈ 1.139,  e^0.58 ≈ 1.786,  e^0.39 ≈ 1.477&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sum ≈ 4.402&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;probs = [1.139/4.402, 1.786/4.402, 1.477/4.402]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      ≈ [0.259, 0.406, 0.336]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;true class: index 1 (probability = 0.406)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;loss = -log(0.406) ≈ 0.902&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Training reduces this loss by adjusting &lt;code&gt;W&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; using gradient descent.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;key-takeaways&quot;&gt;Key Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;probability distribution&lt;/strong&gt; describes how likely each possible outcome is. Probabilities sum to 1.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Gaussian (normal) distribution&lt;/strong&gt; is defined by mean &lt;code&gt;μ&lt;/code&gt; and standard deviation &lt;code&gt;σ&lt;/code&gt;. It appears everywhere because of the Central Limit Theorem.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Softmax&lt;/strong&gt; converts raw logits to probabilities: &lt;code&gt;e^zᵢ / Σ e^zⱼ&lt;/code&gt;. Always positive, always sums to 1.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Temperature&lt;/strong&gt; controls how sharp or flat the softmax output is.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cross-entropy loss&lt;/strong&gt; &lt;code&gt;= -log(ŷ_correct)&lt;/code&gt; measures how wrong a prediction is. High when the model assigns low probability to the true class.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With vectors, derivatives, and probability in hand, you’re ready to build an actual neural network from scratch. That’s next.&lt;/p&gt;</content:encoded></item><item><title>A Neural Network from Scratch: Perceptrons, Layers, and Forward Pass</title><link>https://abhimanyunagurkar.com/blog/math-for-ml-4-neural-networks-from-scratch/</link><guid isPermaLink="true">https://abhimanyunagurkar.com/blog/math-for-ml-4-neural-networks-from-scratch/</guid><description>Build a neural network layer by layer — the perceptron, activation functions (ReLU, sigmoid, tanh), and a complete worked forward pass.</description><pubDate>Sun, 10 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The previous three posts gave you vectors, matrices, derivatives, and probability. Now you have everything needed to build and run a neural network from scratch — no libraries, just arithmetic.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-perceptron-one-neuron&quot;&gt;The Perceptron: One Neuron&lt;/h2&gt;
&lt;p&gt;A single neuron takes a vector of inputs, multiplies each by a weight, adds a bias, and passes the result through an activation function.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;z = w₁x₁ + w₂x₂ + ... + wₙxₙ + b&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;a = activation(z)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In matrix form (using the dot product):&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;z = w · x + b&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;a = activation(z)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where &lt;code&gt;w&lt;/code&gt; and &lt;code&gt;x&lt;/code&gt; are vectors of the same length, and &lt;code&gt;b&lt;/code&gt; is a scalar.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Worked example:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;x = [0.5, 1.2, -0.3]       # input (3 features)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;w = [0.4, -0.1, 0.8]       # weights&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;b = 0.2                      # bias&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;z = (0.4×0.5) + (-0.1×1.2) + (0.8×-0.3) + 0.2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  = 0.20 - 0.12 - 0.24 + 0.2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  = 0.04&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;a = activation(0.04)        # apply activation function&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The weights &lt;code&gt;w&lt;/code&gt; and bias &lt;code&gt;b&lt;/code&gt; are the parameters that training will learn. A single neuron can only learn a &lt;strong&gt;linear decision boundary&lt;/strong&gt; — it separates space with a line (or hyperplane). That’s why we stack neurons into layers and add nonlinear activations.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;activation-functions&quot;&gt;Activation Functions&lt;/h2&gt;
&lt;p&gt;Without activation functions, stacking layers is pointless: &lt;code&gt;W₂(W₁x + b₁) + b₂&lt;/code&gt; is still just a linear transformation, equivalent to a single layer. Activations introduce &lt;strong&gt;nonlinearity&lt;/strong&gt;, enabling networks to learn complex patterns.&lt;/p&gt;
&lt;h3 id=&quot;relu-rectified-linear-unit&quot;&gt;ReLU (Rectified Linear Unit)&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ReLU(z) = max(0, z)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the input is positive, pass it through unchanged. If negative, output 0.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ReLU(-2.5) = 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ReLU(0)    = 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ReLU(3.1)  = 3.1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ReLU is the default choice for hidden layers in modern networks. It’s fast to compute and its gradient is either 0 or 1, which makes backpropagation simple.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Derivative of ReLU:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;d/dz ReLU(z) = 1  if z &gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;             = 0  if z &amp;#x3C; 0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(Undefined at &lt;code&gt;z = 0&lt;/code&gt;, but we set it to 0 by convention — rarely matters in practice.)&lt;/p&gt;
&lt;h3 id=&quot;sigmoid&quot;&gt;Sigmoid&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sigmoid(z) = 1 / (1 + e^(-z))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Squashes any input to the range &lt;code&gt;(0, 1)&lt;/code&gt;. Historically used everywhere, now mostly used in output layers for binary classification.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sigmoid(-3) ≈ 0.047&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sigmoid(0)  = 0.5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sigmoid(3)  ≈ 0.953&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Derivative of sigmoid&lt;/strong&gt; (a neat identity):&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;d/dz sigmoid(z) = sigmoid(z) · (1 - sigmoid(z))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;tanh&quot;&gt;tanh&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;tanh(z) = (e^z - e^(-z)) / (e^z + e^(-z))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Squashes to &lt;code&gt;(-1, 1)&lt;/code&gt;. Outputs are centred around 0 (unlike sigmoid, which is centred around 0.5), which makes training easier in some cases.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;tanh(-2) ≈ -0.964&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;tanh(0)  = 0.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;tanh(2)  ≈  0.964&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;from-one-neuron-to-a-layer&quot;&gt;From One Neuron to a Layer&lt;/h2&gt;
&lt;p&gt;A &lt;strong&gt;layer&lt;/strong&gt; applies a weight matrix &lt;code&gt;W&lt;/code&gt; to the input vector &lt;code&gt;x&lt;/code&gt;, adds a bias vector &lt;code&gt;b&lt;/code&gt;, and then applies an activation elementwise.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Z = W @ x + b        # linear transformation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;A = activation(Z)    # nonlinear activation&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the layer takes &lt;code&gt;n&lt;/code&gt; inputs and produces &lt;code&gt;m&lt;/code&gt; outputs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;W&lt;/code&gt; has shape &lt;code&gt;(m, n)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;x&lt;/code&gt; has shape &lt;code&gt;(n,)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;b&lt;/code&gt; has shape &lt;code&gt;(m,)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Z&lt;/code&gt; and &lt;code&gt;A&lt;/code&gt; both have shape &lt;code&gt;(m,)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Worked example — a 2-neuron layer with 3 inputs:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;W = [[ 0.5, -0.2,  0.1],   # shape (2, 3)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     [-0.3,  0.4,  0.7]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;x = [1.0, 2.0, -1.0]       # shape (3,)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;b = [0.1, -0.2]             # shape (2,)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Z = W @ x + b&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  = [(0.5×1 + -0.2×2 + 0.1×-1 + 0.1),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     (-0.3×1 + 0.4×2 + 0.7×-1 + -0.2)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  = [(0.5 - 0.4 - 0.1 + 0.1),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     (-0.3 + 0.8 - 0.7 - 0.2)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  = [0.1, -0.4]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;A = ReLU(Z) = ReLU([0.1, -0.4]) = [0.1, 0.0]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The second neuron got a negative pre-activation, so ReLU clamps it to 0. That neuron is “off” for this input.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;a-complete-2-layer-network&quot;&gt;A Complete 2-Layer Network&lt;/h2&gt;
&lt;p&gt;Now let’s stack two layers and run a full forward pass. The network will classify 2D points into 2 categories.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Architecture:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Input: 2 features&lt;/li&gt;
&lt;li&gt;Hidden layer: 3 neurons, ReLU activation&lt;/li&gt;
&lt;li&gt;Output layer: 2 neurons, softmax (class probabilities)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Layer 1 weights and biases:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;W1 = [[ 0.4, -0.3],     # shape (3, 2)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      [-0.2,  0.5],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      [ 0.8,  0.1]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;b1 = [0.1, -0.1, 0.0]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Layer 2 weights and biases:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;W2 = [[ 0.6, -0.4,  0.2],   # shape (2, 3)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      [-0.1,  0.3,  0.5]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;b2 = [0.0, 0.1]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Input:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;x = [1.5, -0.5]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Forward pass — Layer 1:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Z1 = W1 @ x + b1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Z1[0] = 0.4×1.5 + (-0.3)×(-0.5) + 0.1 = 0.6 + 0.15 + 0.1 = 0.85&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Z1[1] = (-0.2)×1.5 + 0.5×(-0.5) + (-0.1) = -0.3 - 0.25 - 0.1 = -0.65&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Z1[2] = 0.8×1.5 + 0.1×(-0.5) + 0.0 = 1.2 - 0.05 = 1.15&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Z1 = [0.85, -0.65, 1.15]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;A1 = ReLU(Z1) = [0.85, 0.0, 1.15]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The second neuron fired negatively and was clamped to 0 by ReLU.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Forward pass — Layer 2:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Z2 = W2 @ A1 + b2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Z2[0] = 0.6×0.85 + (-0.4)×0.0 + 0.2×1.15 + 0.0 = 0.51 + 0 + 0.23 = 0.74&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Z2[1] = (-0.1)×0.85 + 0.3×0.0 + 0.5×1.15 + 0.1 = -0.085 + 0 + 0.575 + 0.1 = 0.59&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Z2 = [0.74, 0.59]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# softmax&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;e^0.74 = 2.096&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;e^0.59 = 1.804&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sum    = 3.900&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ŷ = [2.096/3.900, 1.804/3.900] = [0.538, 0.463]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The network assigns 53.8% probability to class 0 and 46.3% to class 1.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Computing the loss&lt;/strong&gt; (assuming class 0 is correct):&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;L = -log(ŷ₀) = -log(0.538) = 0.620&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Training will adjust all 14 parameters (&lt;code&gt;W1&lt;/code&gt;, &lt;code&gt;b1&lt;/code&gt;, &lt;code&gt;W2&lt;/code&gt;, &lt;code&gt;b2&lt;/code&gt;) to reduce this loss.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;batched-computation&quot;&gt;Batched Computation&lt;/h2&gt;
&lt;p&gt;In practice, you don’t process one example at a time — you process a &lt;strong&gt;batch&lt;/strong&gt; of many examples simultaneously using matrix operations, which is far more efficient on GPU hardware.&lt;/p&gt;
&lt;p&gt;If your batch has &lt;code&gt;B&lt;/code&gt; examples and each example has &lt;code&gt;n&lt;/code&gt; features, the input &lt;code&gt;X&lt;/code&gt; has shape &lt;code&gt;(B, n)&lt;/code&gt;. The layer computes:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Z = X @ W.T + b     # shape (B, m)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;A = activation(Z)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(Note: &lt;code&gt;X @ W.T&lt;/code&gt; rather than &lt;code&gt;W @ x&lt;/code&gt; because &lt;code&gt;X&lt;/code&gt; has examples as rows, not columns. Both are equivalent for a single example.)&lt;/p&gt;
&lt;p&gt;PyTorch and NumPy handle this transparently:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; numpy &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; np&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# batch of 4 examples, 2 features each&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;X &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; np.array([[&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1.5&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0.5&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;              [&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0.0&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,  &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1.0&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;              [&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1.0&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;2.0&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;              [&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0.5&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,  &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0.5&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]])  &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# shape (4, 2)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;W1 &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; np.array([[ &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0.4&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0.3&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;               [&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0.2&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,  &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0.5&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;               [ &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0.8&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,  &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0.1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]])  &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# shape (3, 2)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;b1 &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; np.array([&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0.1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0.1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0.0&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;Z1 &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; X &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; W1.T &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; b1   &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# shape (4, 3)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;A1 &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; np.maximum(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, Z1)  &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# ReLU, shape (4, 3)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(A1)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All 4 examples are computed simultaneously, in parallel.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;key-takeaways&quot;&gt;Key Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;perceptron&lt;/strong&gt; computes &lt;code&gt;z = w·x + b&lt;/code&gt;, then &lt;code&gt;a = activation(z)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Without activations, stacking layers is equivalent to one linear layer.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ReLU&lt;/strong&gt; &lt;code&gt;max(0,z)&lt;/code&gt; is the default hidden-layer activation — simple, fast, and effective.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sigmoid&lt;/strong&gt; squashes to &lt;code&gt;(0,1)&lt;/code&gt; for binary outputs; &lt;strong&gt;tanh&lt;/strong&gt; squashes to &lt;code&gt;(-1,1)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;layer&lt;/strong&gt; is &lt;code&gt;A = activation(W @ x + b)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;forward pass&lt;/strong&gt; chains these layer computations to produce a prediction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Batching&lt;/strong&gt; processes many examples at once via matrix multiply — essential for GPU efficiency.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The network can now produce predictions. But how does it learn? Next post: backpropagation — where the chain rule does the heavy lifting.&lt;/p&gt;</content:encoded></item><item><title>Backpropagation: How Neural Networks Learn from Mistakes</title><link>https://abhimanyunagurkar.com/blog/math-for-ml-5-backpropagation/</link><guid isPermaLink="true">https://abhimanyunagurkar.com/blog/math-for-ml-5-backpropagation/</guid><description>A complete walkthrough of backpropagation — the chain rule applied to computation graphs. Includes a worked numerical example through a 2-layer network.</description><pubDate>Sun, 10 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The forward pass computes a prediction. The loss measures how wrong it is. Backpropagation answers the question: which weights should change, and in which direction, to reduce the loss?&lt;/p&gt;
&lt;p&gt;The answer comes from the chain rule, applied systematically from the output backward through every layer to every weight. This post walks through that calculation in full.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-computation-graph&quot;&gt;The Computation Graph&lt;/h2&gt;
&lt;p&gt;A neural network is a composition of functions. The easiest way to reason about it is as a &lt;strong&gt;computation graph&lt;/strong&gt;: a directed acyclic graph where each node is an operation and each edge carries a value.&lt;/p&gt;
&lt;p&gt;For a minimal network &lt;code&gt;output = W·x + b → sigmoid → loss&lt;/code&gt;:&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.6.9&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 384 824&quot;&gt;&lt;svg class=&quot;d2-1487021991 d2-svg&quot; width=&quot;384&quot; height=&quot;824&quot; viewBox=&quot;-25 -25 384 824&quot;&gt;&lt;rect x=&quot;-25.000000&quot; y=&quot;-25.000000&quot; width=&quot;384.000000&quot; height=&quot;824.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-1487021991 .text-bold {
	font-family: &quot;d2-1487021991-font-bold&quot;;
}
@font-face {
	font-family: d2-1487021991-font-bold;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-1487021991 .fill-N1{fill:#0A0F25;}
		.d2-1487021991 .fill-N2{fill:#676C7E;}
		.d2-1487021991 .fill-N3{fill:#9499AB;}
		.d2-1487021991 .fill-N4{fill:#CFD2DD;}
		.d2-1487021991 .fill-N5{fill:#DEE1EB;}
		.d2-1487021991 .fill-N6{fill:#EEF1F8;}
		.d2-1487021991 .fill-N7{fill:#FFFFFF;}
		.d2-1487021991 .fill-B1{fill:#0D32B2;}
		.d2-1487021991 .fill-B2{fill:#0D32B2;}
		.d2-1487021991 .fill-B3{fill:#E3E9FD;}
		.d2-1487021991 .fill-B4{fill:#E3E9FD;}
		.d2-1487021991 .fill-B5{fill:#EDF0FD;}
		.d2-1487021991 .fill-B6{fill:#F7F8FE;}
		.d2-1487021991 .fill-AA2{fill:#4A6FF3;}
		.d2-1487021991 .fill-AA4{fill:#EDF0FD;}
		.d2-1487021991 .fill-AA5{fill:#F7F8FE;}
		.d2-1487021991 .fill-AB4{fill:#EDF0FD;}
		.d2-1487021991 .fill-AB5{fill:#F7F8FE;}
		.d2-1487021991 .stroke-N1{stroke:#0A0F25;}
		.d2-1487021991 .stroke-N2{stroke:#676C7E;}
		.d2-1487021991 .stroke-N3{stroke:#9499AB;}
		.d2-1487021991 .stroke-N4{stroke:#CFD2DD;}
		.d2-1487021991 .stroke-N5{stroke:#DEE1EB;}
		.d2-1487021991 .stroke-N6{stroke:#EEF1F8;}
		.d2-1487021991 .stroke-N7{stroke:#FFFFFF;}
		.d2-1487021991 .stroke-B1{stroke:#0D32B2;}
		.d2-1487021991 .stroke-B2{stroke:#0D32B2;}
		.d2-1487021991 .stroke-B3{stroke:#E3E9FD;}
		.d2-1487021991 .stroke-B4{stroke:#E3E9FD;}
		.d2-1487021991 .stroke-B5{stroke:#EDF0FD;}
		.d2-1487021991 .stroke-B6{stroke:#F7F8FE;}
		.d2-1487021991 .stroke-AA2{stroke:#4A6FF3;}
		.d2-1487021991 .stroke-AA4{stroke:#EDF0FD;}
		.d2-1487021991 .stroke-AA5{stroke:#F7F8FE;}
		.d2-1487021991 .stroke-AB4{stroke:#EDF0FD;}
		.d2-1487021991 .stroke-AB5{stroke:#F7F8FE;}
		.d2-1487021991 .background-color-N1{background-color:#0A0F25;}
		.d2-1487021991 .background-color-N2{background-color:#676C7E;}
		.d2-1487021991 .background-color-N3{background-color:#9499AB;}
		.d2-1487021991 .background-color-N4{background-color:#CFD2DD;}
		.d2-1487021991 .background-color-N5{background-color:#DEE1EB;}
		.d2-1487021991 .background-color-N6{background-color:#EEF1F8;}
		.d2-1487021991 .background-color-N7{background-color:#FFFFFF;}
		.d2-1487021991 .background-color-B1{background-color:#0D32B2;}
		.d2-1487021991 .background-color-B2{background-color:#0D32B2;}
		.d2-1487021991 .background-color-B3{background-color:#E3E9FD;}
		.d2-1487021991 .background-color-B4{background-color:#E3E9FD;}
		.d2-1487021991 .background-color-B5{background-color:#EDF0FD;}
		.d2-1487021991 .background-color-B6{background-color:#F7F8FE;}
		.d2-1487021991 .background-color-AA2{background-color:#4A6FF3;}
		.d2-1487021991 .background-color-AA4{background-color:#EDF0FD;}
		.d2-1487021991 .background-color-AA5{background-color:#F7F8FE;}
		.d2-1487021991 .background-color-AB4{background-color:#EDF0FD;}
		.d2-1487021991 .background-color-AB5{background-color:#F7F8FE;}
		.d2-1487021991 .color-N1{color:#0A0F25;}
		.d2-1487021991 .color-N2{color:#676C7E;}
		.d2-1487021991 .color-N3{color:#9499AB;}
		.d2-1487021991 .color-N4{color:#CFD2DD;}
		.d2-1487021991 .color-N5{color:#DEE1EB;}
		.d2-1487021991 .color-N6{color:#EEF1F8;}
		.d2-1487021991 .color-N7{color:#FFFFFF;}
		.d2-1487021991 .color-B1{color:#0D32B2;}
		.d2-1487021991 .color-B2{color:#0D32B2;}
		.d2-1487021991 .color-B3{color:#E3E9FD;}
		.d2-1487021991 .color-B4{color:#E3E9FD;}
		.d2-1487021991 .color-B5{color:#EDF0FD;}
		.d2-1487021991 .color-B6{color:#F7F8FE;}
		.d2-1487021991 .color-AA2{color:#4A6FF3;}
		.d2-1487021991 .color-AA4{color:#EDF0FD;}
		.d2-1487021991 .color-AA5{color:#F7F8FE;}
		.d2-1487021991 .color-AB4{color:#EDF0FD;}
		.d2-1487021991 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-1487021991);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-1487021991);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-1487021991);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-1487021991);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-1487021991);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-1487021991);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-1487021991);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-1487021991);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-1487021991);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-1487021991);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-1487021991);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-1487021991);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-1487021991);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-1487021991);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-1487021991);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-1487021991);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-1487021991);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-1487021991);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;eA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;0.000000&quot; y=&quot;0.000000&quot; width=&quot;105.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;52.500000&quot; y=&quot;38.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;x (input)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;dw==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;165.000000&quot; y=&quot;0.000000&quot; width=&quot;121.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;225.500000&quot; y=&quot;38.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;W (weight)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Yg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;238.000000&quot; y=&quot;172.000000&quot; width=&quot;96.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;286.000000&quot; y=&quot;210.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;b (bias)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;bXVs&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;ellipse rx=&quot;38.500000&quot; ry=&quot;38.500000&quot; cx=&quot;139.500000&quot; cy=&quot;204.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;shape stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/ellipse&gt;&lt;/g&gt;&lt;text x=&quot;139.500000&quot; y=&quot;210.000000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;×&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;YWRk&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;ellipse rx=&quot;38.500000&quot; ry=&quot;38.500000&quot; cx=&quot;212.500000&quot; cy=&quot;381.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;shape stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/ellipse&gt;&lt;/g&gt;&lt;text x=&quot;212.500000&quot; y=&quot;387.000000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;+&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;c2ln&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;ellipse rx=&quot;38.500000&quot; ry=&quot;38.500000&quot; cx=&quot;212.500000&quot; cy=&quot;558.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;shape stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/ellipse&gt;&lt;/g&gt;&lt;text x=&quot;212.500000&quot; y=&quot;564.000000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;σ&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;bG9zcw==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;ellipse rx=&quot;38.500000&quot; ry=&quot;38.500000&quot; cx=&quot;212.500000&quot; cy=&quot;735.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;shape stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/ellipse&gt;&lt;/g&gt;&lt;text x=&quot;212.500000&quot; y=&quot;741.000000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;L&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KHggLSZndDsgbXVsKVswXQ==&quot;&gt;&lt;marker id=&quot;mk-d2-1487021991-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 52.500000 68.000000 C 52.500000 106.000000 64.400002 128.199005 109.207027 174.136558&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1487021991-3488378134)&quot; mask=&quot;url(#d2-1487021991)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KHcgLSZndDsgbXVsKVswXQ==&quot;&gt;&lt;path d=&quot;M 225.500000 68.000000 C 225.500000 106.000000 213.600006 128.199005 168.792973 174.136558&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1487021991-3488378134)&quot; mask=&quot;url(#d2-1487021991)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KG11bCAtJmd0OyBhZGQpWzBd&quot;&gt;&lt;path d=&quot;M 139.000000 245.000000 C 139.000000 283.000000 148.800003 304.799988 185.444396 348.922844&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1487021991-3488378134)&quot; mask=&quot;url(#d2-1487021991)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KGIgLSZndDsgYWRkKVswXQ==&quot;&gt;&lt;path d=&quot;M 285.500000 240.500000 C 285.500000 282.100006 275.799988 304.799988 239.540074 348.910012&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1487021991-3488378134)&quot; mask=&quot;url(#d2-1487021991)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KGFkZCAtJmd0OyBzaWcpWzBd&quot;&gt;&lt;path d=&quot;M 212.010000 421.999975 C 212.199997 460.000000 212.199997 480.000000 212.019999 516.000050&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1487021991-3488378134)&quot; mask=&quot;url(#d2-1487021991)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KHNpZyAtJmd0OyBsb3NzKVswXQ==&quot;&gt;&lt;path d=&quot;M 212.010000 598.999975 C 212.199997 637.000000 212.199997 657.000000 212.019999 693.000050&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1487021991-3488378134)&quot; mask=&quot;url(#d2-1487021991)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;mask id=&quot;d2-1487021991&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;384&quot; height=&quot;824&quot;&gt;
&lt;rect x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;384&quot; height=&quot;824&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;22.500000&quot; y=&quot;22.500000&quot; width=&quot;60&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;187.500000&quot; y=&quot;22.500000&quot; width=&quot;76&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;260.500000&quot; y=&quot;194.500000&quot; width=&quot;51&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;135.500000&quot; y=&quot;194.000000&quot; width=&quot;8&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;208.500000&quot; y=&quot;371.000000&quot; width=&quot;8&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;208.000000&quot; y=&quot;548.000000&quot; width=&quot;9&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;209.000000&quot; y=&quot;725.000000&quot; width=&quot;7&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Forward pass&lt;/strong&gt;: values flow left to right; we compute and store each intermediate result.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Backward pass&lt;/strong&gt;: gradients flow right to left; at each node we apply the chain rule and multiply the incoming gradient by the local derivative.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-key-idea-local-gradients&quot;&gt;The Key Idea: Local Gradients&lt;/h2&gt;
&lt;p&gt;At each node in the graph, we only need to know:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The &lt;strong&gt;local gradient&lt;/strong&gt; — how the node’s output changes with respect to its input.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;upstream gradient&lt;/strong&gt; — how the loss changes with respect to this node’s output (arriving from the right).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Then, by the chain rule:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;gradient flowing backward = upstream gradient × local gradient&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the entire algorithm. Let’s work through it.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;worked-example-a-single-neuron&quot;&gt;Worked Example: A Single Neuron&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Setup:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;x = 2.0, w = -3.0, b = -3.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;z = w·x + b&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ŷ = sigmoid(z)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;L = (ŷ - y)² / 2    (MSE loss, true label y = 0)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Forward pass:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;z  = (-3.0)(2.0) + (-3.0) = -6.0 - 3.0 = -9.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ŷ  = sigmoid(-9.0) = 1/(1+e^9.0) = 1/8104.1 ≈ 0.000123&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;L  = (0.000123 - 0)² / 2 ≈ 0.0000000076   (very small — already close)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s use a worse weight so the gradients are more instructive. Try &lt;code&gt;w = 1.0&lt;/code&gt;, &lt;code&gt;b = 0.5&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;x = 2.0, w = 1.0, b = 0.5, y = 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;z  = 1.0×2.0 + 0.5 = 2.5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ŷ  = sigmoid(2.5) = 1/(1+e^-2.5) = 1/1.082 ≈ 0.924&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;L  = (0.924 - 0)² / 2 = 0.427&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Loss is 0.427. We want to reduce it by adjusting &lt;code&gt;w&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Backward pass — computing ∂L/∂w and ∂L/∂b:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Step 1: gradient of loss with respect to &lt;code&gt;ŷ&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂L/∂ŷ = ŷ - y = 0.924 - 0 = 0.924&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Step 2: gradient through sigmoid. Using the identity &lt;code&gt;sigmoid&apos;(z) = sigmoid(z)·(1-sigmoid(z))&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂ŷ/∂z = sigmoid(2.5)·(1 - sigmoid(2.5)) = 0.924 × 0.076 = 0.0702&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂L/∂z = ∂L/∂ŷ · ∂ŷ/∂z = 0.924 × 0.0702 = 0.0649&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Step 3: gradient through the linear layer &lt;code&gt;z = wx + b&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂z/∂w = x = 2.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂z/∂b = 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂L/∂w = ∂L/∂z · ∂z/∂w = 0.0649 × 2.0 = 0.1298&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂L/∂b = ∂L/∂z · ∂z/∂b = 0.0649 × 1.0 = 0.0649&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Gradient descent update&lt;/strong&gt; (with &lt;code&gt;η = 0.5&lt;/code&gt;):&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;w ← 1.0 - 0.5 × 0.1298 = 1.0 - 0.0649 = 0.9351&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;b ← 0.5 - 0.5 × 0.0649 = 0.5 - 0.0325 = 0.4675&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After one update, let’s check the new loss:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;z  = 0.9351×2.0 + 0.4675 = 2.337&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ŷ  = sigmoid(2.337) ≈ 0.912&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;L  = 0.912² / 2 = 0.416    (was 0.427 — improved slightly)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After thousands of such steps, the loss converges toward 0.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;backprop-through-a-2-layer-network&quot;&gt;Backprop Through a 2-Layer Network&lt;/h2&gt;
&lt;p&gt;Now let’s extend this to the 2-layer network from the previous post. The structure:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;x → [W1, b1, ReLU] → A1 → [W2, b2, Softmax] → ŷ → Cross-Entropy → L&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using the values from post 4’s forward pass:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;x  = [1.5, -0.5]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Z1 = [0.85, -0.65, 1.15]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;A1 = [0.85, 0.0, 1.15]      (after ReLU)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Z2 = [0.74, 0.59]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ŷ  = [0.538, 0.463]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;y  = [1, 0]                  (class 0 is correct)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;L  = -log(0.538) = 0.620&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Backward pass:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: gradient of cross-entropy + softmax (combined)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The combined gradient of cross-entropy loss + softmax has a beautifully clean form:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂L/∂Z2 = ŷ - y = [0.538-1, 0.463-0] = [-0.462, 0.463]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is one of the most elegant results in neural network math — the gradient is just the prediction error.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2: gradient w.r.t. W2 and b2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For each weight &lt;code&gt;W2[i,j]&lt;/code&gt;, the gradient is the product of the upstream gradient at output &lt;code&gt;i&lt;/code&gt; and the input activation at position &lt;code&gt;j&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂L/∂W2[i, j] = (∂L/∂Z2)[i] × A1[j]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# Row 0 (output neuron 0):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂L/∂W2[0, :] = -0.462 × [0.85, 0.0, 1.15] = [-0.393, 0.0, -0.531]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# Row 1 (output neuron 1):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂L/∂W2[1, :] =  0.463 × [0.85, 0.0, 1.15] = [ 0.394, 0.0,  0.532]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂L/∂b2 = ∂L/∂Z2 = [-0.462, 0.463]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 3: gradient flowing back to A1&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂L/∂A1 = W2ᵀ @ (∂L/∂Z2)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;W2ᵀ has shape (3, 2), ∂L/∂Z2 has shape (2,)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂L/∂A1[0] = 0.6×(-0.462) + (-0.1)×0.463 = -0.277 - 0.046 = -0.323&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂L/∂A1[1] = (-0.4)×(-0.462) + 0.3×0.463 = 0.185 + 0.139 = 0.324&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂L/∂A1[2] = 0.2×(-0.462) + 0.5×0.463  = -0.092 + 0.232 = 0.140&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 4: gradient through ReLU&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;ReLU’s derivative is 1 where &lt;code&gt;Z1 &gt; 0&lt;/code&gt; and 0 where &lt;code&gt;Z1 ≤ 0&lt;/code&gt;. This is the &lt;strong&gt;ReLU mask&lt;/strong&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Z1 = [0.85, -0.65, 1.15]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;mask = [1, 0, 1]              (1 where Z1 &gt; 0, 0 elsewhere)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂L/∂Z1 = ∂L/∂A1 × mask = [-0.323, 0.0, 0.140]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The second neuron was inactive (ReLU output was 0), so no gradient flows through it. This is correct — if a neuron doesn’t contribute to the output, adjusting its weights has no effect on the loss.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 5: gradient w.r.t. W1 and b1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Same pattern as Step 2 — multiply the upstream gradient by each input feature:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂L/∂W1[i, j] = (∂L/∂Z1)[i] × x[j]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂L/∂W1[0, :] = -0.323 × [1.5, -0.5] = [-0.485,  0.162]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂L/∂W1[1, :] =  0.0   × [1.5, -0.5] = [ 0.0,    0.0  ]   (zeroed by ReLU mask)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂L/∂W1[2, :] =  0.140 × [1.5, -0.5] = [ 0.210, -0.070]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;∂L/∂b1 = ∂L/∂Z1 = [-0.323, 0.0, 0.140]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-pattern&quot;&gt;The Pattern&lt;/h2&gt;
&lt;p&gt;Every layer in a neural network has the same two ingredients:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Forward&lt;/strong&gt;: &lt;code&gt;Z = W @ A_prev + b&lt;/code&gt;, &lt;code&gt;A = activation(Z)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backward&lt;/strong&gt;: receive &lt;code&gt;∂L/∂A&lt;/code&gt; from the next layer, compute &lt;code&gt;∂L/∂W&lt;/code&gt;, &lt;code&gt;∂L/∂b&lt;/code&gt; (for gradient updates), and &lt;code&gt;∂L/∂A_prev&lt;/code&gt; (to pass backward further).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The backward pass is just the chain rule applied layer by layer, starting from the loss and working back to every weight.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;why-backpropagation&quot;&gt;Why “Backpropagation”?&lt;/h2&gt;
&lt;p&gt;The word comes from “backward propagation of errors.” Information about the loss is propagated backward through the network to every weight. Each weight receives a gradient proportional to how much it contributed to the error.&lt;/p&gt;
&lt;p&gt;Weights that contributed a lot to a large error get a large gradient and are adjusted significantly. Weights that barely affected the output get nearly zero gradient and change little. The network naturally focuses learning on the parameters that matter most.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;practical-implementation&quot;&gt;Practical Implementation&lt;/h2&gt;
&lt;p&gt;In PyTorch, this is handled automatically:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; torch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;x  &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; torch.tensor([&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1.5&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0.5&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;y  &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; torch.tensor([&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1.0&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0.0&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Define weights with gradient tracking&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;W1 &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; torch.randn(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;requires_grad&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;True&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;b1 &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; torch.zeros(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;requires_grad&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;True&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;W2 &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; torch.randn(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;requires_grad&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;True&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;b2 &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; torch.zeros(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;requires_grad&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;True&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Forward pass&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;A1 &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; torch.relu(W1 &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; b1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;Z2 &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; W2 &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; A1 &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; b2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;probs &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; torch.softmax(Z2, &lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;dim&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;loss &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;torch.log(probs[&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;])   &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# true class is index 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Backward pass — PyTorch computes all gradients automatically&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;loss.backward()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Gradients are now in W1.grad, b1.grad, W2.grad, b2.grad&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(W1.grad)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;loss.backward()&lt;/code&gt; builds and traverses the computation graph, computing every gradient via the chain rule. The code above does exactly what we computed by hand.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;key-takeaways&quot;&gt;Key Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Backpropagation&lt;/strong&gt; is the chain rule applied to a computation graph, starting from the loss and moving backward through each layer.&lt;/li&gt;
&lt;li&gt;At each node, the &lt;strong&gt;local gradient&lt;/strong&gt; × &lt;strong&gt;upstream gradient&lt;/strong&gt; gives the gradient to pass further back.&lt;/li&gt;
&lt;li&gt;The gradient of &lt;strong&gt;cross-entropy + softmax&lt;/strong&gt; is simply &lt;code&gt;ŷ - y&lt;/code&gt; — the prediction error.&lt;/li&gt;
&lt;li&gt;The gradient through &lt;strong&gt;ReLU&lt;/strong&gt; is either 1 (pass through) or 0 (blocked). Neurons with negative pre-activations don’t update their weights.&lt;/li&gt;
&lt;li&gt;Every weight receives a gradient proportional to its contribution to the error.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With backpropagation understood, you know how neural networks learn. The next two posts cover the specific techniques that make large language models work: embeddings and attention.&lt;/p&gt;</content:encoded></item><item><title>Embeddings and Similarity: Turning Words into Vectors</title><link>https://abhimanyunagurkar.com/blog/math-for-ml-6-embeddings-and-similarity/</link><guid isPermaLink="true">https://abhimanyunagurkar.com/blog/math-for-ml-6-embeddings-and-similarity/</guid><description>How neural networks represent words as dense vectors, why dot products measure similarity, and how cosine similarity finds related concepts.</description><pubDate>Sun, 10 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A neural network can only process numbers. Before a language model can reason about the word “cat”, it must be converted into a vector of numbers. This conversion is called an &lt;strong&gt;embedding&lt;/strong&gt;, and the mathematical properties of those vectors are what give language models their apparent ability to understand meaning.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;why-not-just-use-integers&quot;&gt;Why Not Just Use Integers?&lt;/h2&gt;
&lt;p&gt;The simplest approach: assign each word an integer. “cat” = 1, “dog” = 2, “car” = 3.&lt;/p&gt;
&lt;p&gt;This has a fatal problem. The number 3 is larger than 2, which is larger than 1 — but “car” is not more than “dog” in any meaningful sense. Neural networks will try to learn from these numerical relationships and get confused.&lt;/p&gt;
&lt;h3 id=&quot;one-hot-encoding&quot;&gt;One-Hot Encoding&lt;/h3&gt;
&lt;p&gt;A better idea: give each word a vector of zeros with a single 1 at the word’s index.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;vocabulary = [&quot;cat&quot;, &quot;dog&quot;, &quot;car&quot;, &quot;runs&quot;, &quot;sleeps&quot;]  # size = 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;cat&quot;    → [1, 0, 0, 0, 0]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;dog&quot;    → [0, 1, 0, 0, 0]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;car&quot;    → [0, 0, 1, 0, 0]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This fixes the ordering problem — no word is numerically larger than another. But it has two major flaws:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Dimensionality&lt;/strong&gt;: Real vocabularies have 50,000–100,000+ words. Each vector would be 50,000+ dimensions, mostly zeros. Storing and multiplying with these is extremely wasteful.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;No notion of similarity&lt;/strong&gt;: The dot product of any two different one-hot vectors is 0. The model has no way to know that “cat” and “dog” are more related to each other than “cat” and “car”.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&quot;dense-embeddings&quot;&gt;Dense Embeddings&lt;/h2&gt;
&lt;p&gt;The solution: represent each word as a &lt;strong&gt;dense vector&lt;/strong&gt; in a much smaller space, typically 64 to 1024 dimensions. These vectors are learned during training.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;cat&quot;    → [0.2, -0.4,  0.7,  0.1, ...]   # 768-dimensional vector&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;dog&quot;    → [0.3, -0.3,  0.8,  0.0, ...]   # similar to &quot;cat&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;car&quot;    → [-0.5, 0.6, -0.2,  0.9, ...]   # different direction&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Words with similar meanings end up with similar vectors. Words that appear in similar contexts during training pull their vectors together. After training, the geometry of the embedding space encodes semantic relationships.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-embedding-matrix&quot;&gt;The Embedding Matrix&lt;/h2&gt;
&lt;p&gt;In practice, embeddings are stored in an &lt;strong&gt;embedding matrix&lt;/strong&gt; &lt;code&gt;E&lt;/code&gt; of shape &lt;code&gt;(vocab_size, embedding_dim)&lt;/code&gt;. Row &lt;code&gt;i&lt;/code&gt; of &lt;code&gt;E&lt;/code&gt; is the embedding vector for word with index &lt;code&gt;i&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To look up the embedding for word &lt;code&gt;i&lt;/code&gt;, multiply the one-hot vector &lt;code&gt;eᵢ&lt;/code&gt; by &lt;code&gt;E&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;embedding = eᵢ @ E&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But multiplying a one-hot vector by a matrix just selects a row — it’s equivalent to a table lookup:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;embedding = E[i, :]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is all an embedding layer does: look up a row in a learned table. The parameters &lt;code&gt;E&lt;/code&gt; are learned through backpropagation, just like any other weights.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In PyTorch:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; torch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; torch.nn &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; nn&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;vocab_size &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 10000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;embed_dim  &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 256&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;embedding_layer &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; nn.Embedding(vocab_size, embed_dim)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Look up embeddings for a batch of token indices&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;token_ids &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; torch.tensor([&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;17&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;42&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;])  &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# 4 tokens&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;embeddings &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; embedding_layer(token_ids)    &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# shape (4, 256)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;dot-product-as-similarity&quot;&gt;Dot Product as Similarity&lt;/h2&gt;
&lt;p&gt;From post 1, the dot product of two vectors &lt;code&gt;a · b = |a||b|cos(θ)&lt;/code&gt;. The dot product is large when vectors point in the same direction and small (or negative) when they don’t.&lt;/p&gt;
&lt;p&gt;This makes it a natural similarity measure:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sim(&quot;cat&quot;, &quot;dog&quot;)  = cat_vec · dog_vec  ≈ large positive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sim(&quot;cat&quot;, &quot;car&quot;)  = cat_vec · car_vec  ≈ small&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sim(&quot;cat&quot;, &quot;hate&quot;) = cat_vec · hate_vec ≈ small or negative&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The dot product is used directly in the attention mechanism (post 7).&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;cosine-similarity&quot;&gt;Cosine Similarity&lt;/h2&gt;
&lt;p&gt;The dot product depends on the magnitude of both vectors. A long vector will have large dot products with everything. &lt;strong&gt;Cosine similarity&lt;/strong&gt; normalises for this:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cosine_sim(a, b) = (a · b) / (|a| × |b|)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where &lt;code&gt;|a|&lt;/code&gt; is the length (L2 norm) of vector &lt;code&gt;a&lt;/code&gt;: &lt;code&gt;|a| = sqrt(a[0]² + a[1]² + ... + a[n]²)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The result is always between -1 and +1:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;+1&lt;/code&gt; — same direction (identical meaning).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0&lt;/code&gt; — perpendicular (unrelated).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-1&lt;/code&gt; — opposite directions (opposite meaning).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Worked example:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;a = [0.6, 0.8]    (embedding for &quot;king&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;b = [0.5, 0.9]    (embedding for &quot;queen&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;c = [-0.9, 0.2]   (embedding for &quot;terrible&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;a · b = 0.6×0.5 + 0.8×0.9 = 0.30 + 0.72 = 1.02&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;|a| = sqrt(0.6² + 0.8²) = sqrt(0.36 + 0.64) = 1.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;|b| = sqrt(0.5² + 0.9²) = sqrt(0.25 + 0.81) = sqrt(1.06) ≈ 1.03&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cosine_sim(a, b) = 1.02 / (1.0 × 1.03) ≈ 0.99   ← very similar&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;a · c = 0.6×(-0.9) + 0.8×0.2 = -0.54 + 0.16 = -0.38&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;|c| = sqrt(0.81 + 0.04) = sqrt(0.85) ≈ 0.92&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cosine_sim(a, c) = -0.38 / (1.0 × 0.92) ≈ -0.41   ← dissimilar&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;semantic-arithmetic&quot;&gt;Semantic Arithmetic&lt;/h2&gt;
&lt;p&gt;One of the most surprising properties of trained embeddings is that &lt;strong&gt;arithmetic on vectors corresponds to semantic relationships&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The classic example:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;embedding(&quot;king&quot;) - embedding(&quot;man&quot;) + embedding(&quot;woman&quot;) ≈ embedding(&quot;queen&quot;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The embedding space has learned to encode the concept of “royalty” and “gender” as directions in space. Subtracting the “man” direction and adding the “woman” direction finds the nearby word “queen”.&lt;/p&gt;
&lt;p&gt;Other examples:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Paris - France + Germany ≈ Berlin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;walking - walk + swim ≈ swimming&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;puppy - dog + cat ≈ kitten&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These relationships are not explicitly programmed. They emerge from training on large corpora, because words that appear in similar contexts end up with similar vector directions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A caveat:&lt;/strong&gt; because embeddings are shaped entirely by the text they were trained on, they also absorb biases present in that text. Early word embeddings notoriously encoded sexist and racist stereotypes (e.g. &lt;code&gt;doctor - man + woman ≈ nurse&lt;/code&gt;). Modern models partially mitigate this with curated training data and additional fine-tuning, but it remains an active area of research.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;subword-tokenisation&quot;&gt;Subword Tokenisation&lt;/h2&gt;
&lt;p&gt;Modern language models don’t embed whole words — they embed &lt;strong&gt;subword tokens&lt;/strong&gt;. The word “unbelievable” might be tokenised as &lt;code&gt;[&quot;un&quot;, &quot;believ&quot;, &quot;able&quot;]&lt;/code&gt;, and each subword gets its own embedding. This handles rare words and morphology automatically.&lt;/p&gt;
&lt;p&gt;GPT-2 uses &lt;strong&gt;Byte Pair Encoding (BPE)&lt;/strong&gt;, which builds a vocabulary of common character sequences. GPT-4 uses a similar approach. The vocabulary size is typically 50,000–100,000 tokens.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;positional-embeddings&quot;&gt;Positional Embeddings&lt;/h2&gt;
&lt;p&gt;Embeddings give each word an identity, but they carry no positional information — the embedding of “cat” is the same whether it appears first or last in a sentence. Transformers solve this by adding a &lt;strong&gt;positional embedding&lt;/strong&gt; to each token’s embedding:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;final_embedding[i] = token_embedding[i] + positional_embedding[i]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The positional embeddings encode the position of each token in the sequence. Post 8 covers how these are constructed.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;key-takeaways&quot;&gt;Key Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;One-hot encoding&lt;/strong&gt; is sparse and carries no semantic information. Dot products between one-hot vectors are always 0 or 1.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dense embeddings&lt;/strong&gt; are learned vectors of typically 64–1024 dimensions. Similar words get similar vectors.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;embedding matrix&lt;/strong&gt; &lt;code&gt;E&lt;/code&gt; stores one row per vocabulary word. Looking up an embedding is just indexing a row.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;dot product&lt;/strong&gt; &lt;code&gt;a · b&lt;/code&gt; measures how much two vectors point in the same direction — the foundation of attention.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cosine similarity&lt;/strong&gt; normalises for vector length, giving a similarity score in &lt;code&gt;[-1, +1]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Trained embeddings exhibit &lt;strong&gt;semantic arithmetic&lt;/strong&gt;: &lt;code&gt;king - man + woman ≈ queen&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next: the attention mechanism — where embeddings meet dot products to build context-aware representations.&lt;/p&gt;</content:encoded></item><item><title>The Attention Mechanism: How Transformers Focus</title><link>https://abhimanyunagurkar.com/blog/math-for-ml-7-attention-mechanism/</link><guid isPermaLink="true">https://abhimanyunagurkar.com/blog/math-for-ml-7-attention-mechanism/</guid><description>A detailed walkthrough of scaled dot-product attention — Query, Key, and Value matrices, the softmax operation, and a complete numerical example.</description><pubDate>Sun, 10 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Before transformers, recurrent neural networks processed sequences one token at a time. To remember something from 100 words ago, the information had to survive through 100 sequential updates — often fading or being overwritten. The attention mechanism solves this by allowing every position in the sequence to directly attend to every other position, in a single step.&lt;/p&gt;
&lt;p&gt;The math behind this is elegant and entirely built from tools you already have: matrix multiplication, dot products, and softmax.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-problem-context-dependent-meaning&quot;&gt;The Problem: Context-Dependent Meaning&lt;/h2&gt;
&lt;p&gt;The word “bank” means different things in:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;I deposited money in the bank&quot;     → financial institution&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;I sat by the river bank&quot;           → side of a river&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For a language model to process “bank” correctly, it needs to know which other words in the sentence are relevant. That’s what attention computes.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-library-analogy&quot;&gt;The Library Analogy&lt;/h2&gt;
&lt;p&gt;Imagine a library system:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You arrive with a &lt;strong&gt;query&lt;/strong&gt; — what you’re looking for.&lt;/li&gt;
&lt;li&gt;Every book has a &lt;strong&gt;key&lt;/strong&gt; — a label describing its contents.&lt;/li&gt;
&lt;li&gt;Each book also has a &lt;strong&gt;value&lt;/strong&gt; — the actual content.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The system compares your query to every key, figures out which books are most relevant, and returns a weighted blend of those books’ values.&lt;/p&gt;
&lt;p&gt;Attention works exactly the same way:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Q (Query)&lt;/strong&gt;: what this position is looking for.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;K (Key)&lt;/strong&gt;: what each position offers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;V (Value)&lt;/strong&gt;: the actual content each position contributes.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;scaled-dot-product-attention&quot;&gt;Scaled Dot-Product Attention&lt;/h2&gt;
&lt;p&gt;The full formula:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Attention(Q, K, V) = softmax(QKᵀ / √dₖ) · V&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where &lt;code&gt;dₖ&lt;/code&gt; is the dimension of the key vectors.&lt;/p&gt;
&lt;p&gt;This looks concise but unpacks into four meaningful steps:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Compute attention scores&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;scores = Q @ Kᵀ&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each entry &lt;code&gt;scores[i, j]&lt;/code&gt; is the dot product of query &lt;code&gt;i&lt;/code&gt; with key &lt;code&gt;j&lt;/code&gt; — how relevant position &lt;code&gt;j&lt;/code&gt; is to position &lt;code&gt;i&lt;/code&gt;. Shape: &lt;code&gt;(seq_len, seq_len)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Scale&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;scores = scores / √dₖ&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Why scale? The dot product of two &lt;code&gt;dₖ&lt;/code&gt;-dimensional vectors has variance that grows with &lt;code&gt;dₖ&lt;/code&gt;. Without scaling, large &lt;code&gt;dₖ&lt;/code&gt; values push the dot products into regions where softmax produces near-zero gradients (the “saturated” region). Dividing by &lt;code&gt;√dₖ&lt;/code&gt; keeps the variance stable regardless of dimension.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Softmax to get weights&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;weights = softmax(scores, applied row by row)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each row of &lt;code&gt;weights&lt;/code&gt; is a probability distribution over all positions. &lt;code&gt;weights[i, j]&lt;/code&gt; is how much position &lt;code&gt;i&lt;/code&gt; should attend to position &lt;code&gt;j&lt;/code&gt;. Each row sums to 1.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4: Weighted sum of values&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;output = weights @ V&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Position &lt;code&gt;i&lt;/code&gt;’s output is a weighted average of all value vectors, weighted by how much &lt;code&gt;i&lt;/code&gt; should attend to each position.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;a-worked-numerical-example&quot;&gt;A Worked Numerical Example&lt;/h2&gt;
&lt;p&gt;Sequence: “the cat sat” — 3 tokens. Embedding dimension &lt;code&gt;dₖ = 4&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Input embeddings (3 × 4):&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;X = [[0.9, 0.3, 0.1, 0.5],    # &quot;the&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     [0.1, 0.8, 0.4, 0.2],    # &quot;cat&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     [0.6, 0.1, 0.9, 0.3]]    # &quot;sat&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In practice, Q, K, V are computed by multiplying &lt;code&gt;X&lt;/code&gt; by learned weight matrices &lt;code&gt;Wq&lt;/code&gt;, &lt;code&gt;Wk&lt;/code&gt;, &lt;code&gt;Wv&lt;/code&gt;. For simplicity, let’s use &lt;code&gt;Q = K = V = X&lt;/code&gt; (which is what happens when those weight matrices are identity matrices).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Scores = Q @ Kᵀ&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Kᵀ (transposed, shape 4×3):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[[0.9, 0.1, 0.6],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; [0.3, 0.8, 0.1],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; [0.1, 0.4, 0.9],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; [0.5, 0.2, 0.3]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Scores = X @ Kᵀ (shape 3×3):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;scores[0,0] = 0.9×0.9 + 0.3×0.3 + 0.1×0.1 + 0.5×0.5 = 0.81+0.09+0.01+0.25 = 1.16&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;scores[0,1] = 0.9×0.1 + 0.3×0.8 + 0.1×0.4 + 0.5×0.2 = 0.09+0.24+0.04+0.10 = 0.47&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;scores[0,2] = 0.9×0.6 + 0.3×0.1 + 0.1×0.9 + 0.5×0.3 = 0.54+0.03+0.09+0.15 = 0.81&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;scores[1,0] = 0.1×0.9 + 0.8×0.3 + 0.4×0.1 + 0.2×0.5 = 0.09+0.24+0.04+0.10 = 0.47&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;scores[1,1] = 0.1×0.1 + 0.8×0.8 + 0.4×0.4 + 0.2×0.2 = 0.01+0.64+0.16+0.04 = 0.85&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;scores[1,2] = 0.1×0.6 + 0.8×0.1 + 0.4×0.9 + 0.2×0.3 = 0.06+0.08+0.36+0.06 = 0.56&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;scores[2,0] = 0.6×0.9 + 0.1×0.3 + 0.9×0.1 + 0.3×0.5 = 0.54+0.03+0.09+0.15 = 0.81&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;scores[2,1] = 0.6×0.1 + 0.1×0.8 + 0.9×0.4 + 0.3×0.2 = 0.06+0.08+0.36+0.06 = 0.56&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;scores[2,2] = 0.6×0.6 + 0.1×0.1 + 0.9×0.9 + 0.3×0.3 = 0.36+0.01+0.81+0.09 = 1.27&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Scores:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[[1.16, 0.47, 0.81],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; [0.47, 0.85, 0.56],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; [0.81, 0.56, 1.27]]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Scale by √dₖ = √4 = 2&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Scaled scores:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[[0.58, 0.235, 0.405],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; [0.235, 0.425, 0.28],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; [0.405, 0.28, 0.635]]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Softmax (row by row)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For row 0: &lt;code&gt;[0.58, 0.235, 0.405]&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;e^0.58 = 1.786, e^0.235 = 1.265, e^0.405 = 1.500&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sum = 4.551&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;weights[0] = [1.786/4.551, 1.265/4.551, 1.500/4.551]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;           = [0.393, 0.278, 0.330]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For row 1: &lt;code&gt;[0.235, 0.425, 0.28]&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;e^0.235 = 1.265, e^0.425 = 1.530, e^0.28 = 1.323&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sum = 4.118&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;weights[1] = [0.307, 0.371, 0.321]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For row 2: &lt;code&gt;[0.405, 0.28, 0.635]&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;e^0.405 = 1.500, e^0.28 = 1.323, e^0.635 = 1.887&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sum = 4.710&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;weights[2] = [0.318, 0.281, 0.401]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Attention weights:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[[0.393, 0.278, 0.330],   &quot;the&quot; attends to: the(39%), cat(28%), sat(33%)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; [0.307, 0.371, 0.321],   &quot;cat&quot; attends to: the(31%), cat(37%), sat(32%)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; [0.318, 0.281, 0.401]]   &quot;sat&quot; attends to: the(32%), cat(28%), sat(40%)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each position attends most strongly to itself (the diagonal), but also gathers information from other positions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4: Output = weights @ V&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;V = X&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;output[0] = 0.393×[0.9,0.3,0.1,0.5] + 0.278×[0.1,0.8,0.4,0.2] + 0.330×[0.6,0.1,0.9,0.3]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          = [0.354,0.118,0.039,0.197] + [0.028,0.222,0.111,0.056] + [0.198,0.033,0.297,0.099]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          = [0.580, 0.373, 0.447, 0.352]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;output[0]&lt;/code&gt; is now a blend of all three value vectors, weighted by how relevant each token is to “the”. The embedding for “the” has been enriched with contextual information from the whole sentence.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;causal-masking-gpt-style&quot;&gt;Causal Masking (GPT-style)&lt;/h2&gt;
&lt;p&gt;GPT generates text left to right. When predicting the next token, it must not be able to see future tokens. This is enforced with a &lt;strong&gt;causal mask&lt;/strong&gt;: before the softmax, positions are blocked from attending to future positions by adding &lt;code&gt;-∞&lt;/code&gt; to those scores.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Masked scores for sequence &quot;the cat sat&quot;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[[0.58,  -inf, -inf],   &quot;the&quot; can only see itself&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; [0.235, 0.425, -inf],  &quot;cat&quot; can see &quot;the&quot; and itself&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; [0.405, 0.28,  0.635]] &quot;sat&quot; can see all three&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;softmax(-inf) = 0&lt;/code&gt;, so those positions get zero weight. The model genuinely cannot leak information from the future.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;multi-head-attention&quot;&gt;Multi-Head Attention&lt;/h2&gt;
&lt;p&gt;Running attention once captures one type of relationship. &lt;strong&gt;Multi-head attention&lt;/strong&gt; runs &lt;code&gt;h&lt;/code&gt; parallel attention computations (“heads”), each with its own learned &lt;code&gt;Wq&lt;/code&gt;, &lt;code&gt;Wk&lt;/code&gt;, &lt;code&gt;Wv&lt;/code&gt; matrices, then concatenates and projects the results.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;head_i = Attention(X·Wqᵢ, X·Wkᵢ, X·Wvᵢ)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;MultiHead(X) = Concat(head_1, ..., head_h) · Wo&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Different heads learn to attend to different types of relationships simultaneously:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One head might focus on syntactic dependencies.&lt;/li&gt;
&lt;li&gt;Another on semantic similarity.&lt;/li&gt;
&lt;li&gt;Another on positional proximity.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;GPT-2 (small) uses 12 heads each of dimension 64, for a total dimension of 768.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;key-takeaways&quot;&gt;Key Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Attention computes a context-aware representation of each position by attending to all other positions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Q&lt;/strong&gt; (query), &lt;strong&gt;K&lt;/strong&gt; (key), &lt;strong&gt;V&lt;/strong&gt; (value) are linear projections of the input embeddings.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scaled dot-product attention&lt;/strong&gt;: &lt;code&gt;softmax(QKᵀ / √dₖ) · V&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Scaling by &lt;code&gt;√dₖ&lt;/code&gt; prevents the dot products from growing too large and saturating softmax.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Causal masking&lt;/strong&gt; prevents future positions from influencing past predictions — essential for autoregressive text generation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-head attention&lt;/strong&gt; runs &lt;code&gt;h&lt;/code&gt; attention heads in parallel, each learning different relationships.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The final post puts everything together into the full transformer architecture — and walks through exactly what GPT does on every forward pass.&lt;/p&gt;</content:encoded></item><item><title>The Transformer and GPT: Putting It All Together</title><link>https://abhimanyunagurkar.com/blog/math-for-ml-8-transformer-and-gpt/</link><guid isPermaLink="true">https://abhimanyunagurkar.com/blog/math-for-ml-8-transformer-and-gpt/</guid><description>Multi-head attention, positional encoding, layer normalisation, and the feed-forward sublayer. A complete step-by-step forward pass through GPT.</description><pubDate>Sun, 10 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;You now have every mathematical tool needed to understand GPT. Vectors and matrices (post 1) move data. Derivatives and gradients (post 2) drive learning. Probability and softmax (post 3) produce predictions. Layers with activations (post 4) learn nonlinear functions. Backpropagation (post 5) trains all the weights. Embeddings (post 6) represent words. Attention (post 7) builds contextual representations.&lt;/p&gt;
&lt;p&gt;This post assembles these pieces into the transformer architecture and walks through a complete forward pass.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-transformer-block&quot;&gt;The Transformer Block&lt;/h2&gt;
&lt;p&gt;The core unit of a transformer is the &lt;strong&gt;transformer block&lt;/strong&gt; (also called a transformer layer). GPT stacks many of these in sequence.&lt;/p&gt;
&lt;p&gt;Each block has two sublayers:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Multi-Head Self-Attention&lt;/strong&gt; — lets positions attend to each other.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feed-Forward Network&lt;/strong&gt; — processes each position independently with a two-layer MLP.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each sublayer is wrapped with two important additions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;residual connection&lt;/strong&gt; (add the input to the output).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Layer normalisation&lt;/strong&gt; (applied before each sublayer).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The full computation for one block:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# Sub-layer 1: Multi-Head Attention&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;X&apos; = X + MultiHeadAttention(LayerNorm(X))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# Sub-layer 2: Feed-Forward Network&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;X&apos;&apos; = X&apos; + FFN(LayerNorm(X&apos;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;layer-normalisation&quot;&gt;Layer Normalisation&lt;/h2&gt;
&lt;p&gt;Layer normalisation stabilises training by ensuring the activations at each layer have a consistent distribution, regardless of the scale of the previous layer’s outputs.&lt;/p&gt;
&lt;p&gt;For a vector &lt;code&gt;x&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;μ = mean(x)           # mean of all elements&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;σ = std(x)            # standard deviation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;x_norm = (x - μ) / σ  # normalise&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;output = γ · x_norm + β   # learnable scale γ and shift β&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;γ&lt;/code&gt; and &lt;code&gt;β&lt;/code&gt; are learned parameters (each a vector of length &lt;code&gt;d_model&lt;/code&gt;). After normalising, the network can still learn to rescale and shift the distribution as needed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Worked example (4-dimensional vector):&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;x = [0.5, -0.3, 1.2, 0.8]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;μ = (0.5 - 0.3 + 1.2 + 0.8) / 4 = 2.2 / 4 = 0.55&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;σ = sqrt(((0.5-0.55)² + (-0.3-0.55)² + (1.2-0.55)² + (0.8-0.55)²) / 4)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  = sqrt((0.0025 + 0.7225 + 0.4225 + 0.0625) / 4)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  = sqrt(0.3025) = 0.55&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;x_norm = [(0.5-0.55)/0.55, (-0.3-0.55)/0.55, (1.2-0.55)/0.55, (0.8-0.55)/0.55]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       = [-0.091, -1.545, 1.182, 0.455]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# With γ = [1,1,1,1] and β = [0,0,0,0], output = x_norm&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Without LayerNorm, deep networks become difficult to train because small changes in early layers compound through many subsequent layers, causing exploding or vanishing gradients.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;residual-connections&quot;&gt;Residual Connections&lt;/h2&gt;
&lt;p&gt;A residual connection adds the sublayer’s input directly to its output:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;output = x + Sublayer(x)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This looks simple but has a profound effect: during backpropagation, gradients can flow directly from the output back to any earlier layer without being diminished by each intermediate layer. This is why transformers with dozens of layers can be trained at all.&lt;/p&gt;
&lt;p&gt;Without residuals, training a 96-layer transformer (like GPT-3) would be practically impossible — gradients would vanish long before reaching the early layers.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-feed-forward-network&quot;&gt;The Feed-Forward Network&lt;/h2&gt;
&lt;p&gt;The FFN sublayer is a standard two-layer MLP applied independently to each position’s vector:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;FFN(x) = ReLU(x · W₁ + b₁) · W₂ + b₂&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(This post uses the row-vector convention &lt;code&gt;x · W&lt;/code&gt;, common in transformer papers. It’s equivalent to &lt;code&gt;Wᵀ @ x&lt;/code&gt; from the earlier posts — just with the matrix transposed.)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;W₁&lt;/code&gt; has shape &lt;code&gt;(d_model, d_ff)&lt;/code&gt; — expands to a larger dimension.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;W₂&lt;/code&gt; has shape &lt;code&gt;(d_ff, d_model)&lt;/code&gt; — projects back.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;d_ff&lt;/code&gt; is typically &lt;code&gt;4 × d_model&lt;/code&gt;. In GPT-2 small: &lt;code&gt;d_model = 768&lt;/code&gt;, &lt;code&gt;d_ff = 3072&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The FFN is applied &lt;strong&gt;position-wise&lt;/strong&gt;: each token’s vector goes through the same MLP independently. It does not mix information across positions — that’s attention’s job.&lt;/p&gt;
&lt;p&gt;The expansion to &lt;code&gt;4×d_model&lt;/code&gt; gives the network capacity to store complex transformations. Research suggests the FFN layers act as associative memories, storing factual knowledge in their weights.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;positional-encoding&quot;&gt;Positional Encoding&lt;/h2&gt;
&lt;p&gt;Attention has no built-in sense of position — the operation &lt;code&gt;softmax(QKᵀ/√dₖ)V&lt;/code&gt; is identical regardless of token order. Position is injected by adding a positional encoding to each token’s embedding before it enters the transformer stack.&lt;/p&gt;
&lt;p&gt;The original transformer paper (Vaswani et al. 2017) uses sinusoidal functions:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;PE(pos, 2i)   = sin(pos / 10000^(2i/d_model))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;PE(pos, 2i+1) = cos(pos / 10000^(2i/d_model))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where &lt;code&gt;pos&lt;/code&gt; is the token position and &lt;code&gt;i&lt;/code&gt; is the dimension index.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why sinusoids?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Each position gets a unique pattern of sine/cosine values.&lt;/li&gt;
&lt;li&gt;The model can generalise to sequence lengths not seen during training.&lt;/li&gt;
&lt;li&gt;Relative positions can be represented as linear transformations of absolute positions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;GPT-2 uses &lt;strong&gt;learned positional embeddings&lt;/strong&gt; instead: a separate embedding matrix of shape &lt;code&gt;(max_seq_len, d_model)&lt;/code&gt; where each row is a trainable vector. Both approaches work; learned embeddings are simpler.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-full-gpt-forward-pass&quot;&gt;The Full GPT Forward Pass&lt;/h2&gt;
&lt;p&gt;GPT is a &lt;strong&gt;decoder-only&lt;/strong&gt; transformer. It takes a sequence of tokens and predicts the next token.&lt;/p&gt;
&lt;p&gt;Let’s trace through GPT-2 Small (12 layers, 12 heads, &lt;code&gt;d_model = 768&lt;/code&gt;):&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Input:&lt;/strong&gt; the sequence “The cat sat on the”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Tokenise and embed&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;tokens = [464, 3797, 3332, 319, 262]   # BPE token ids&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# 464=&quot;The&quot;, 3797=&quot;cat&quot;, 3332=&quot;sat&quot;, 319=&quot;on&quot;, 262=&quot;the&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# Look up token embeddings:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;E = embedding_matrix[tokens]           # shape (5, 768)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# Add positional embeddings:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;P = positional_matrix[[0,1,2,3,4]]     # shape (5, 768)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;X = E + P                              # shape (5, 768)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Pass through 12 transformer blocks&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For each block &lt;code&gt;i&lt;/code&gt; in &lt;code&gt;[0..11]&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# Attention sublayer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;X_norm = LayerNorm(X)                   # shape (5, 768)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;attn_out = MultiHeadAttention(X_norm)   # shape (5, 768)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;X = X + attn_out                        # residual&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# FFN sublayer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;X_norm = LayerNorm(X)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ffn_out = FFN(X_norm)                   # shape (5, 768)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;X = X + ffn_out                         # residual&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After 12 blocks, &lt;code&gt;X&lt;/code&gt; still has shape &lt;code&gt;(5, 768)&lt;/code&gt;, but each token’s vector is now a rich contextual representation incorporating information from all other tokens.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Final layer norm + linear projection&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;X_final = LayerNorm(X)                  # shape (5, 768)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;logits = X_final @ W_unembed            # shape (5, 50257)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;W_unembed&lt;/code&gt; has shape &lt;code&gt;(768, 50257)&lt;/code&gt; — one column per vocabulary token. (In practice, GPT ties this to the transposed embedding matrix to save parameters.)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4: Sample the next token&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We only need the last position’s logits (predicting what comes after “the”):&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;last_logits = logits[-1]                # shape (50257,)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;probs = softmax(last_logits / T)        # T = temperature (post 3)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;next_token = sample(probs)              # e.g., &quot;mat&quot; (token 17680)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The model outputs “mat” — completing “The cat sat on the mat.”&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;parameter-count&quot;&gt;Parameter Count&lt;/h2&gt;
&lt;p&gt;Let’s understand where GPT-2 Small’s 117M parameters come from:&lt;/p&gt;









































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Component&lt;/th&gt;&lt;th&gt;Parameters&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Token embeddings&lt;/td&gt;&lt;td&gt;50,257 × 768 = 38.6M&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Positional embeddings&lt;/td&gt;&lt;td&gt;1,024 × 768 = 0.8M&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Per block: Attention (Q,K,V,O matrices)&lt;/td&gt;&lt;td&gt;4 × (768 × 768) = 2.4M&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Per block: FFN (W₁, W₂)&lt;/td&gt;&lt;td&gt;(768×3072) + (3072×768) = 4.7M&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Per block: LayerNorms&lt;/td&gt;&lt;td&gt;≈ 0.003M&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;12 blocks × (2.4 + 4.7)M&lt;/td&gt;&lt;td&gt;85.2M&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Final LayerNorm + unembedding&lt;/td&gt;&lt;td&gt;≈ 0.6M&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;≈ 117M&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;GPT-3 uses 175 billion parameters — the same architecture, scaled up: 96 layers, 96 heads, &lt;code&gt;d_model = 12,288&lt;/code&gt;. Every forward pass still executes the same sequence of operations you now understand.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;what-training-actually-does&quot;&gt;What Training Actually Does&lt;/h2&gt;
&lt;p&gt;During training on a large text corpus, the loss is the average cross-entropy across all positions (here &lt;code&gt;N&lt;/code&gt; is sequence length):&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;L = -(1/N) Σₜ log P(tokenₜ | token₁, ..., tokenₜ₋₁)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For each training step:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Run a forward pass on a batch of sequences.&lt;/li&gt;
&lt;li&gt;Compute the cross-entropy loss.&lt;/li&gt;
&lt;li&gt;Run backpropagation to compute gradients for all 117M parameters.&lt;/li&gt;
&lt;li&gt;Update all parameters with gradient descent (usually Adam optimiser).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After training on hundreds of billions of tokens, the weights encode enough statistical structure about language that the model can answer questions, write code, translate, summarise, and reason — all from next-token prediction.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;key-takeaways&quot;&gt;Key Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;transformer block&lt;/strong&gt; = MultiHeadAttention + FFN, each wrapped with LayerNorm and a residual connection.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Layer normalisation&lt;/strong&gt; stabilises training by keeping activations at a consistent scale.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Residual connections&lt;/strong&gt; allow gradients to flow directly to early layers, making deep networks trainable.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;FFN sublayer&lt;/strong&gt; applies a two-layer MLP at each position independently, with hidden dimension &lt;code&gt;4×d_model&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Positional encoding&lt;/strong&gt; injects position information by adding sinusoidal or learned vectors to token embeddings.&lt;/li&gt;
&lt;li&gt;GPT is decoder-only: it predicts the next token autoregressively using a causally masked transformer stack.&lt;/li&gt;
&lt;li&gt;One forward pass = embed → position encode → N×(LayerNorm+Attention+Residual+LayerNorm+FFN+Residual) → linear → softmax.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You now have the complete mathematical picture of how GPT works, built from nothing but addition, multiplication, and the chain rule. Every “emergent” capability in a language model traces back to these operations, repeated billions of times on billions of tokens.&lt;/p&gt;</content:encoded></item><item><title>People, Character, and the Foundation of Learning</title><link>https://abhimanyunagurkar.com/blog/how-to-get-rich-part-5-people-character-learning/</link><guid isPermaLink="true">https://abhimanyunagurkar.com/blog/how-to-get-rich-part-5-people-character-learning/</guid><description>Who to build with, why long-term games compound everything, and how to build the reading habit that underpins Naval Ravikant&apos;s entire framework.</description><pubDate>Thu, 07 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; This post is part of a personal learning series based on Naval Ravikant’s &lt;em&gt;“How to Get Rich”&lt;/em&gt; transcript, available at &lt;a href=&quot;https://nav.al/rich&quot;&gt;nav.al/rich&lt;/a&gt;. The ideas and frameworks here belong to Naval — I’m working through them for my own understanding. This is not financial advice.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;Strategy, leverage, and specific knowledge are built individually. But wealth at any meaningful scale is built with people, over time. The final layer of Naval’s framework is about who to build with, how trust compounds when you play long games, and how to develop the intellectual foundation that makes everything else possible.&lt;/p&gt;
&lt;h2 id=&quot;play-long-term-games-with-long-term-people&quot;&gt;Play Long-Term Games With Long-Term People&lt;/h2&gt;
&lt;p&gt;Naval’s observation about compound interest extends far beyond money: &lt;strong&gt;all the benefits in life come from compound interest&lt;/strong&gt; — in relationships, in knowledge, and in reputation, not just in investments.&lt;/p&gt;
&lt;p&gt;The reason long-term games compound is game theory. In a one-shot interaction, the rational move is often to defect — extract maximum value and move on, because there are no future rounds to lose. In a repeated game with the same people, the rational move is to cooperate, because both sides know the game continues. Trust develops precisely because both parties have skin in future iterations.&lt;/p&gt;
&lt;p&gt;This dynamic is what Naval points to when describing Silicon Valley’s productivity. Long-term geographic proximity — encountering the same people across companies, across deals, across decades — changes how people behave toward each other. Reputation follows you. Defection in round one affects every subsequent round. The result is a tit-for-tat equilibrium where cooperation is the dominant strategy, not because of idealism but because of rational self-interest across a long time horizon.&lt;/p&gt;
&lt;p&gt;In long-term games, &lt;strong&gt;everyone makes each other wealthier&lt;/strong&gt; — positive sum. In short-term games, people divide what already exists — zero sum. The type of game you’re playing determines what strategy is rational.&lt;/p&gt;
&lt;p&gt;The corollary is the cost of switching too frequently: every time you reset your context — new industry, new city, new network — you start compounding from zero. The trust you’ve built, the reputation you’ve earned, the relationships that took years to develop don’t transfer. They compound in place. People who switch industries and geographies repeatedly never benefit from the long tail of compounding that comes from sustained presence in one domain and community.&lt;/p&gt;
&lt;h2 id=&quot;pick-partners-with-intelligence-energy-and-integrity&quot;&gt;Pick Partners With Intelligence, Energy, and Integrity&lt;/h2&gt;
&lt;p&gt;Naval’s partner selection framework is three non-negotiable traits:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Intelligence&lt;/strong&gt; — seeing problems clearly, acting in the right direction, making sound decisions under uncertainty.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Energy&lt;/strong&gt; — actually executing. Showing up, doing the work, sustaining effort over the duration needed for things to compound.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Integrity&lt;/strong&gt; — not cheating you when it becomes advantageous to do so.&lt;/p&gt;
&lt;p&gt;All three are required. Any two without the third is dangerous. High intelligence and high energy without integrity produces “a smart and hardworking crook who’s eventually going to cheat you.” The smarter and more energetic they are, the more thoroughly they can cause damage when their interests diverge from yours. Integrity is the constraint that makes the other two safe to rely on.&lt;/p&gt;
&lt;p&gt;The difficulty is that integrity is the hardest trait to verify upfront. People present well in early interactions. The tell is &lt;strong&gt;how they behave when they think no one is watching&lt;/strong&gt;: how they treat people with less power than them, how they handle situations where cutting corners would benefit them, whether they hold grudges out of proportion to the offence, whether they speak badly about people who aren’t in the room.&lt;/p&gt;
&lt;p&gt;These patterns are consistent. The person who treats a waiter dismissively will eventually treat you dismissively. The person who rationalises cheating a previous employer will find a rationalisation for cheating you when the circumstances align. You cannot manufacture high-integrity behaviour through incentives. It either exists in someone’s character or it doesn’t.&lt;/p&gt;
&lt;h2 id=&quot;intrinsic-motivation-cannot-be-manufactured&quot;&gt;Intrinsic Motivation Cannot Be Manufactured&lt;/h2&gt;
&lt;p&gt;A related principle: you cannot sustainably motivate another person through external pressure. Motivation has to come from within. This matters for choosing collaborators because people who are genuinely excited by what they’re building — who would work on it regardless of the specific compensation — sustain output over the long run in a way that externally motivated people don’t.&lt;/p&gt;
&lt;p&gt;External incentives produce performance while the incentive is present. Remove it and performance returns to the intrinsic baseline. If that baseline is low, you’ve built a dependency rather than a partnership.&lt;/p&gt;
&lt;p&gt;The practical consequence: look for people who find the problems genuinely interesting, not primarily those drawn by the package. Their motivation compounds over time. Everyone else’s degrades.&lt;/p&gt;
&lt;h2 id=&quot;partner-with-rational-optimists&quot;&gt;Partner With Rational Optimists&lt;/h2&gt;
&lt;p&gt;Pessimism is the comfortable position. Pointing out why something won’t work requires no execution and insulates you from the embarrassment of trying and failing publicly. Naval identifies the specific failure mode: the cynic who won’t lead, won’t follow, and won’t get out of the way — blocking progress without contributing any direction.&lt;/p&gt;
&lt;p&gt;The alternative isn’t naive optimism — ignoring real risks and charging forward on enthusiasm. It’s &lt;strong&gt;rational optimism&lt;/strong&gt;: seeing reality clearly while maintaining confidence in your ability to navigate it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Know all the pitfalls. Know the downsides, but still keep your chin up.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Naval grounds this in evolutionary reasoning. Humans evolved as pessimists — acute threat sensitivity kept our ancestors alive. But the risk structure of the modern world is fundamentally different: &lt;strong&gt;limited downside, potentially unlimited upside&lt;/strong&gt;. Taking a bet that costs you a year of effort but could generate decade-long returns is rational. The evolved pessimism response — avoid the bet — is no longer calibrated to the actual risk environment.&lt;/p&gt;
&lt;p&gt;The only thing genuinely worth avoiding is ruin: paths that lead to catastrophic, irreversible loss — bankruptcy, jail, permanent reputation damage. Everything short of that is recoverable. Rational optimists understand this distinction and take the bets. Pessimists avoid all of them to preserve the feeling of safety.&lt;/p&gt;
&lt;p&gt;One more observation: successful people “just do things.” The fastest way to determine whether something is viable is to try it. Doing is faster than planning, and far faster than watching.&lt;/p&gt;
&lt;h2 id=&quot;read-what-you-love-until-you-love-to-read&quot;&gt;Read What You Love Until You Love to Read&lt;/h2&gt;
&lt;p&gt;The intellectual foundation of the entire framework is reading — not as a performance but as a compounding habit that changes how you think over years and decades.&lt;/p&gt;
&lt;p&gt;The barrier most people face isn’t access to books. It’s that they haven’t built the habit itself. Naval’s solution to the catch-22: &lt;strong&gt;read what you love until you love to read&lt;/strong&gt;. Start with fiction if that’s what holds attention. Move to science fiction, then narrative non-fiction, then denser material, then primary scientific and philosophical texts. Follow genuine interest rather than a curated syllabus.&lt;/p&gt;
&lt;p&gt;What to read once the habit exists matters. Naval is specific: &lt;strong&gt;read foundational texts over modern commentary&lt;/strong&gt;. Adam Smith’s &lt;em&gt;Wealth of Nations&lt;/em&gt; rather than business school summaries. Darwin’s &lt;em&gt;Origin of Species&lt;/em&gt; rather than popular science books about evolution. Feynman’s &lt;em&gt;Six Easy Pieces&lt;/em&gt; rather than cosmology written for a general audience.&lt;/p&gt;
&lt;p&gt;The reason is fidelity. Every layer of commentary filters, selects, and interprets what came before. Reading the original means encountering the argument as its author constructed it — not as someone else decided to summarise it. You build mental models from primary sources, which are defensible from first principles. Memorised conclusions from secondary sources are not.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Depth over volume.&lt;/strong&gt; It is better to read one book slowly, struggling with difficult passages, sitting with ideas until they become part of how you think, than to skim fifty books and accumulate the count. The goal is not to have read things — it’s to understand them well enough that the insight is available when you need it. That only happens through genuine engagement.&lt;/p&gt;
&lt;h2 id=&quot;mathematics-and-logic-are-the-bedrock&quot;&gt;Mathematics and Logic Are the Bedrock&lt;/h2&gt;
&lt;p&gt;Underlying everything else: mathematics and logic. Once you’ve internalised mathematical thinking, you can evaluate any field’s claims from first principles rather than memorising expert opinions. You can follow a statistical argument to its assumptions, identify what’s being asserted versus what’s been demonstrated, and separate truth from opinion dressed as fact.&lt;/p&gt;
&lt;p&gt;This is the difference between genuine understanding and accumulated information. Someone with mathematical fluency reads a study and evaluates the methodology. Someone without it has to trust the presenter’s summary — which may or may not be accurate.&lt;/p&gt;
&lt;p&gt;Five skills Naval considers foundational for operating effectively in the current world: &lt;strong&gt;reading, writing, arithmetic, persuasion, and computer programming&lt;/strong&gt;. Not a specific domain. Not a specific credential. Five general capabilities that make every other form of learning faster and every other skill more deployable. Master these and the specific content of your career remains flexible across decades.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;The full framework, taken together: define wealth correctly, engineer the conditions for luck, build ownership not just income, develop specific knowledge through genuine curiosity, deploy it through permissionless leverage, play long games with high-integrity people, and compound your understanding through deep reading. None of it is a shortcut. All of it compounds.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Part 5 of 5. Start from the beginning with &lt;a href=&quot;/blog/how-to-get-rich-part-1-wealth-money-status/&quot;&gt;Part 1: Wealth, Money, and Status&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Full original transcript: &lt;a href=&quot;https://nav.al/rich&quot;&gt;nav.al/rich&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title>Leverage, Scale, and What the Internet Changed</title><link>https://abhimanyunagurkar.com/blog/how-to-get-rich-part-4-leverage-scale-internet/</link><guid isPermaLink="true">https://abhimanyunagurkar.com/blog/how-to-get-rich-part-4-leverage-scale-internet/</guid><description>Specific knowledge is the what. Leverage is the how. The four types, why code and media are permissionless, and what the internet permanently changed.</description><pubDate>Wed, 06 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; This post is part of a personal learning series based on Naval Ravikant’s &lt;em&gt;“How to Get Rich”&lt;/em&gt; transcript, available at &lt;a href=&quot;https://nav.al/rich&quot;&gt;nav.al/rich&lt;/a&gt;. The ideas and frameworks here belong to Naval — I’m working through them for my own understanding. This is not financial advice.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;Specific knowledge tells you what to build. Leverage tells you how that knowledge can generate returns that dwarf the time you put in. Without leverage, even exceptional skill produces linear returns — more hours, proportionally more output. With it, one unit of effort can multiply into thousands. This is the mechanism that separates income from wealth.&lt;/p&gt;
&lt;h2 id=&quot;give-society-what-it-doesnt-know-how-to-get&quot;&gt;Give Society What It Doesn’t Know How to Get&lt;/h2&gt;
&lt;p&gt;Before getting to leverage itself, it helps to understand what you’re deploying it toward. Naval’s framing for identifying opportunity: &lt;strong&gt;find things society wants but doesn’t yet have a reliable way to obtain&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If society already knew how to produce something reliably, it would already exist at scale. The gap between what people want and what they can currently get is where value is created. Oil made Rockefeller wealthy because it solved lighting and energy problems that no existing infrastructure addressed. Cars made Ford wealthy because affordable personal transport didn’t exist. Each era has its equivalent gaps.&lt;/p&gt;
&lt;p&gt;Creation alone isn’t enough though — distribution matters equally. Uber didn’t invent private drivers. It removed the friction in accessing them and made that access affordable at scale. The wealth came from solving both the product and the distribution problem. When you find your gap, the question isn’t just “can I build this?” but “can I scale it to the people who need it?”&lt;/p&gt;
&lt;h2 id=&quot;the-four-types-of-leverage&quot;&gt;The Four Types of Leverage&lt;/h2&gt;
&lt;p&gt;Leverage is getting outputs disproportionate to your inputs. Naval identifies four types, and understanding the differences between them matters practically.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Labour leverage&lt;/strong&gt; — other people working on your behalf. The oldest form of leverage. A general commanding an army, a founder building a team. It scales, but slowly and expensively. Every person added requires hiring, onboarding, motivating, and coordinating. Managing people is a skill in itself, and it has hard limits. At some point, communication overhead consumes the gains.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Capital leverage&lt;/strong&gt; — money working on your behalf through investments. More scalable than labour: once deployed, capital doesn’t need management in the same way. But it requires capital to start with, and the returns are heavily competed over by people with access to the same markets and information. Capital leverage alone tends to compress toward market returns over time. It’s powerful, but not distinctive.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Code leverage&lt;/strong&gt; — software running on your behalf at essentially zero marginal cost per additional user. Write a program once; it runs for millions of people simultaneously. This is qualitatively different from labour and capital. The millionth user costs nothing more than the first. A single engineer’s output can serve a global user base without any proportional increase in effort. The upside is uncapped in a way that neither labour nor capital leverage achieves.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Media leverage&lt;/strong&gt; — content working on your behalf. A blog post, a book, a podcast, a video — created once, distributable indefinitely. Joe Rogan records one conversation; it reaches tens of millions of people. The creator is asleep while the content is being consumed. Like code, the marginal cost of an additional listener or reader is zero.&lt;/p&gt;
&lt;h2 id=&quot;permissionless-leverage-is-the-real-unlock&quot;&gt;Permissionless Leverage Is the Real Unlock&lt;/h2&gt;
&lt;p&gt;Naval draws a distinction that matters more than the specific type: &lt;strong&gt;permissionless leverage vs. leverage that requires permission&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Labour and capital leverage require permission. To hire, you need resources and someone willing to work for you. To deploy capital, you need capital — which means either earning it first or convincing someone else to give it to you. These require gatekeepers to say yes.&lt;/p&gt;
&lt;p&gt;Code and media are permissionless. You don’t need someone’s approval to write software. You don’t need a publishing contract to write content. You don’t need an investor to start a YouTube channel or a blog. The barrier to accessing these forms of leverage is effort and skill, not permission.&lt;/p&gt;
&lt;p&gt;This is new. For most of human history, meaningful leverage required institutional access — a factory, a printing press, a radio station, a bank. Those were expensive and controlled. The internet made code and media leverage available to anyone with a laptop and skill. This is the structural change that makes individual wealth creation more achievable now than at any point before.&lt;/p&gt;
&lt;p&gt;The practical consequence: if you’re choosing where to develop skills, weight heavily toward domains where your output can be distributed digitally at zero marginal cost. Writing, software, video, audio. These are the leverage vehicles that don’t require permission to access.&lt;/p&gt;
&lt;h2 id=&quot;what-the-internet-did-to-career-possibilities&quot;&gt;What the Internet Did to Career Possibilities&lt;/h2&gt;
&lt;p&gt;Before the internet, your potential market was bounded by geography. Specialised expertise could only reach the people physically near you — your city, your industry, your local network. Most niche knowledge generated limited returns because the audience for it was too small in any one place to sustain a career.&lt;/p&gt;
&lt;p&gt;The internet removes that constraint entirely. &lt;strong&gt;Any human is now reachable by any other human.&lt;/strong&gt; Any niche obsession — obscure historical research, hardware hacking, competitive chess strategy, miniature cooking — can reach its global audience. The passionate 50,000 people worldwide who would pay for what you know are now findable. That number is often more than enough to build a sustainable livelihood around.&lt;/p&gt;
&lt;p&gt;This has permanently expanded what a viable career looks like. E-sports players earn competitive salaries. Independent creators build audiences larger than cable news networks. Niche newsletter writers support themselves entirely through subscribers they’ve never met. None of these were structurally possible before the internet dissolved the geographic constraint on distribution.&lt;/p&gt;
&lt;p&gt;The other change: &lt;strong&gt;the economics of niche are now better than the economics of generic&lt;/strong&gt;. Serving a small passionate audience is more sustainable than competing for attention in a crowded mainstream category. Generic content fights for attention against everyone. Specific content finds the people for whom it is exactly right.&lt;/p&gt;
&lt;h2 id=&quot;authenticity-eliminates-competition&quot;&gt;Authenticity Eliminates Competition&lt;/h2&gt;
&lt;p&gt;The usual advice for building an audience or a business is to find an underserved market and position competitively. Naval’s observation cuts past this: &lt;strong&gt;escape competition through authenticity&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Every human is a unique intersection of knowledge, experience, curiosity, and personality. No one else has yours. If you build around what you genuinely are — rather than optimising for what seems most commercially validated — you become irreplaceable by definition. The specific combination of you cannot be replicated, so competition converges to zero.&lt;/p&gt;
&lt;p&gt;The trap is the opposite instinct: looking at what’s working for someone else and copying the format, the style, the positioning. That path leads directly into competition with the original, on their terms, where they have the advantage of being first and authentic to the approach. The thing that made them successful is that it’s genuinely theirs. Copying it makes you the imitation.&lt;/p&gt;
&lt;p&gt;This is harder in practice than in principle because authenticity requires resisting a strong social pull. When something works for others, the obvious move is to do the same thing. Resisting that and building from your actual interests and strengths is the thing that generates genuine differentiation.&lt;/p&gt;
&lt;p&gt;Taken together: find the gap society needs filled, build specific knowledge around it, deploy it through permissionless leverage (code or media), reach a global niche through the internet, and let your authentic combination of skills and perspective eliminate direct competition. Each element enables the others.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Part 4 of 5. Read &lt;a href=&quot;/blog/how-to-get-rich-part-3-specific-knowledge/&quot;&gt;Part 3: Specific Knowledge Is Your Moat&lt;/a&gt; or continue to &lt;a href=&quot;/blog/how-to-get-rich-part-5-people-character-learning/&quot;&gt;Part 5: People, Character, and the Foundation of Learning&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title>Specific Knowledge Is Your Moat</title><link>https://abhimanyunagurkar.com/blog/how-to-get-rich-part-3-specific-knowledge/</link><guid isPermaLink="true">https://abhimanyunagurkar.com/blog/how-to-get-rich-part-3-specific-knowledge/</guid><description>The skills that make you irreplaceable cannot be taught in classrooms. Naval on specific knowledge, skill stacking, and why build plus sell beats either alone.</description><pubDate>Tue, 05 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; This post is part of a personal learning series based on Naval Ravikant’s &lt;em&gt;“How to Get Rich”&lt;/em&gt; transcript, available at &lt;a href=&quot;https://nav.al/rich&quot;&gt;nav.al/rich&lt;/a&gt;. The ideas and frameworks here belong to Naval — I’m working through them for my own understanding. This is not financial advice.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;Once you understand what wealth is and why ownership matters, the next question is: what do you actually build expertise in? Naval’s answer is specific knowledge — and the definition is precise enough to be actionable.&lt;/p&gt;
&lt;h2 id=&quot;what-specific-knowledge-is-and-isnt&quot;&gt;What Specific Knowledge Is (And Isn’t)&lt;/h2&gt;
&lt;p&gt;Specific knowledge is expertise that cannot be formally taught, and therefore cannot be mass-produced, commoditised, or automated away.&lt;/p&gt;
&lt;p&gt;The distinction Naval draws: &lt;strong&gt;everything can be learned, but not everything can be taught&lt;/strong&gt;. Specific knowledge is developed through lived experience, genuine obsession, and working at the edge of a domain — not through standardised curricula. If a skill can be taught in a classroom, it can be certified, systematised, scaled, and eventually wage-compressed. The moment a skill becomes teachable at scale, it loses its economic scarcity.&lt;/p&gt;
&lt;p&gt;This is why conventional career advice — study the high-paying field, get the credential, join the sector — often leads to exactly the outcome it promises initially but no more. You end up in a competitive pool of similarly credentialled people, competing on marginal differences.&lt;/p&gt;
&lt;p&gt;Specific knowledge sits outside that pool because it can’t be replicated through the same pathway that created it in you.&lt;/p&gt;
&lt;h2 id=&quot;how-to-find-yours&quot;&gt;How to Find Yours&lt;/h2&gt;
&lt;p&gt;The path Naval describes isn’t strategic — it’s introspective.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Specific knowledge is found much more by pursuing your innate talents, your genuine curiosity, and your passion.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The signal isn’t what sounds impressive or pays well. It’s what feels like play to you while appearing as work to others. If a domain pulls your attention regardless of external reward — if you’d explore it whether or not anyone paid you — that’s where specific knowledge forms.&lt;/p&gt;
&lt;p&gt;There’s also an observational pattern: specific knowledge is often noticed by people who know you well before you’ve identified it yourself. Naval mentions his mother observing his entrepreneurial nature as a child — critiquing pizza parlour operations, noticing inefficiencies. He hadn’t framed it that way. She had. The people closest to you often see your specific knowledge before you do.&lt;/p&gt;
&lt;p&gt;The practical test: find the intersection of what you’re obsessively curious about and what you can get better at faster than most people around you. That’s the seed.&lt;/p&gt;
&lt;h2 id=&quot;skill-stacking&quot;&gt;Skill Stacking&lt;/h2&gt;
&lt;p&gt;You don’t have to be the world’s best at one thing. Naval references Scott Adams’ framework: being in the top 25% at three different skills creates a competitive advantage that doesn’t exist if you’re pursuing any one of them in isolation.&lt;/p&gt;
&lt;p&gt;The combination matters more than the individual rank. A software engineer who is also an excellent communicator and has deep domain knowledge in a specific industry is rarer than three separate people occupying those positions. When the need for that intersection arrives, you’re the only candidate.&lt;/p&gt;
&lt;p&gt;This also means specific knowledge can be assembled over time, across roles and domains, through genuine curiosity rather than linear credential accumulation. The unconventional path creates the unconventional combination.&lt;/p&gt;
&lt;h2 id=&quot;build-and-sell--the-most-powerful-combination&quot;&gt;Build and Sell — The Most Powerful Combination&lt;/h2&gt;
&lt;p&gt;Naval identifies the two fundamental skills of wealth creation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Building&lt;/strong&gt; — creating products, writing code, designing systems, making things that work&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Selling&lt;/strong&gt; — distributing, communicating, recruiting, fundraising, persuading&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The most successful companies pair these in complementary founders. Jobs and Wozniak. Gates and Allen. One who builds deeply, one who sells effectively. The pairing works because each skill is genuinely hard, and most people are strong in at most one.&lt;/p&gt;
&lt;p&gt;But one person who masters both becomes, in Naval’s word, “unstoppable.” Elon Musk understands rockets well enough to make credible commitments. Steve Jobs developed product intuition alongside distribution genius. Marc Andreessen programmed Netscape, then built the firm that funds the next generation.&lt;/p&gt;
&lt;p&gt;The sequence Naval recommends: &lt;strong&gt;learn to build first, then learn to sell&lt;/strong&gt;. Building requires sustained focus and is harder to acquire late. Selling — defined broadly as writing, marketing, communication, and persuasion — can be layered on later, particularly for people who are naturally communicative.&lt;/p&gt;
&lt;p&gt;He goes further: “I’d rather teach an engineer marketing than a marketer engineering.” Technical depth provides better initial differentiation. Engineers who develop sales skills scale better over time than non-technical salespeople who attempt to understand what they’re selling.&lt;/p&gt;
&lt;p&gt;Selling also doesn’t require hand-to-hand interaction. Writing is a form of sales. A clear technical blog post, a well-argued README, a compelling product page — these are all distribution. Engineers uncomfortable with traditional sales often find leverage through writing, which scales without continuous personal effort.&lt;/p&gt;
&lt;h2 id=&quot;there-is-no-skill-called-business&quot;&gt;There Is No Skill Called “Business”&lt;/h2&gt;
&lt;p&gt;Naval is direct about this: &lt;strong&gt;“business” is too broad to mean anything&lt;/strong&gt;, in the same way that “relating to humans” is too broad to be a skill.&lt;/p&gt;
&lt;p&gt;Business schools teach case studies — anecdotes presented as analysis. The problem with anecdotes is that they can be assembled to justify almost any conclusion. Case study education produces pattern-matched intuition that breaks down in novel situations, which is precisely where most interesting business challenges arise.&lt;/p&gt;
&lt;p&gt;The fields worth studying instead:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Microeconomics&lt;/strong&gt; — how individuals and firms make decisions under constraints&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Game theory&lt;/strong&gt; — how strategic actors behave when outcomes depend on others’ choices&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Psychology&lt;/strong&gt; — how people actually think and make decisions (rather than how they should)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Persuasion&lt;/strong&gt; — the mechanics of changing minds&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ethics&lt;/strong&gt; — not as philosophy but as a guide to sustainable decision-making&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mathematics and logic&lt;/strong&gt; — the foundation that lets you evaluate any domain’s truth claims&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Computing&lt;/strong&gt; — the leverage tool of the current era&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are generative rather than descriptive. Understanding microeconomics lets you reason about any market. Understanding game theory lets you think through any negotiation. Understanding psychology applies everywhere. Knowing a specific case study from 1995 applies almost nowhere.&lt;/p&gt;
&lt;p&gt;The deeper principle: &lt;strong&gt;doing is faster than watching&lt;/strong&gt;. Building something, even something small, teaches more than an equivalent amount of time spent reading about what others built. First-principles understanding — built through doing — is defensible from any angle. Memorised facts from case studies are not.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Part 3 of 5. Read &lt;a href=&quot;/blog/how-to-get-rich-part-2-luck-you-can-engineer/&quot;&gt;Part 2: The Luck You Can Engineer&lt;/a&gt; or continue to &lt;a href=&quot;/blog/how-to-get-rich-part-4-leverage-scale-internet/&quot;&gt;Part 4: Leverage, Scale, and the Internet&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title>The Luck You Can Engineer</title><link>https://abhimanyunagurkar.com/blog/how-to-get-rich-part-2-luck-you-can-engineer/</link><guid isPermaLink="true">https://abhimanyunagurkar.com/blog/how-to-get-rich-part-2-luck-you-can-engineer/</guid><description>Naval Ravikant identifies four types of luck — most of the ones that matter for wealth are ones you can systematically engineer.</description><pubDate>Mon, 04 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; This post is part of a personal learning series based on Naval Ravikant’s &lt;em&gt;“How to Get Rich”&lt;/em&gt; transcript, available at &lt;a href=&quot;https://nav.al/rich&quot;&gt;nav.al/rich&lt;/a&gt;. The ideas and frameworks here belong to Naval — I’m working through them for my own understanding. This is not financial advice.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;The phrase “how to get rich without getting lucky” sounds like a contradiction. But Naval’s argument is more precise than it first appears — not that luck doesn’t exist, but that there are four distinct types, and most of the ones that matter are ones you can engineer through deliberate effort.&lt;/p&gt;
&lt;h2 id=&quot;four-types-of-luck&quot;&gt;Four Types of Luck&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;1. Blind luck.&lt;/strong&gt; Pure chance. Lightning strikes, you happen to be in the right place. You have no influence over it, and it’s the least interesting type for building wealth — you can’t optimise for it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Luck from hustling.&lt;/strong&gt; You increase your exposure to opportunity by staying in motion — shipping projects, taking meetings, reaching out, trying things. Naval uses the image of stirring a petri dish: the more you stir, the more reactions you create. More activity expands your surface area for things to happen. This type is fully controllable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Luck from preparation.&lt;/strong&gt; You develop expertise deep enough that you recognise opportunities others miss. Two people encounter the same situation; one sees nothing, the other sees a breakthrough. The difference is pattern recognition built from sustained, focused work. Preparation doesn’t create luck — it lets you catch it when it passes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Luck from character.&lt;/strong&gt; You build a specific reputation and identity over time until opportunities seek you out. If you become known as the world’s best expert in a narrow domain, people with relevant problems will find you. The opportunity arrives because of who you are, not what you happened to be doing that day.&lt;/p&gt;
&lt;p&gt;The progression is the point. Each type is more controllable than the last. The fourth type becomes so reliable it stops functioning like luck at all.&lt;/p&gt;
&lt;h2 id=&quot;the-999-out-of-1000-framework&quot;&gt;The 999 Out of 1,000 Framework&lt;/h2&gt;
&lt;p&gt;Naval frames the goal as: &lt;strong&gt;in 1,000 parallel universes, you want to be wealthy in 999 of them&lt;/strong&gt;. Not all of them — some unlucky outcomes are genuinely unavoidable. But 999 out of 1,000.&lt;/p&gt;
&lt;p&gt;That target requires building yourself so thoroughly that luck becomes marginal. The fourth type — character-driven luck — starts becoming deterministic. “Your character becomes your destiny.” When an opportunity arrives that requires your specific skills and reputation, you’re the only plausible candidate. The randomness is gone.&lt;/p&gt;
&lt;p&gt;This connects character to outcome in a way most frameworks miss. Getting rich without getting lucky means building the version of yourself for whom wealth is a natural consequence, not a fortunate accident.&lt;/p&gt;
&lt;h2 id=&quot;you-wont-get-rich-renting-your-time&quot;&gt;You Won’t Get Rich Renting Your Time&lt;/h2&gt;
&lt;p&gt;Even with the right kind of luck, you need the right vehicle. Salaried employment is the wrong one.&lt;/p&gt;
&lt;p&gt;The structural problem is simple: &lt;strong&gt;inputs match outputs directly&lt;/strong&gt;. Sleep, and you earn nothing. Vacation, and you earn nothing. Your output is capped by your hours, your hours are capped by your lifespan, and there is no mechanism for non-linear returns.&lt;/p&gt;
&lt;p&gt;The deeper problem is replaceability. When you take a salaried role, you agree to perform a defined set of functions. Defined functions can be systematised, taught, and eventually automated. You’re filling a role, not expressing a unique capability. Your replacement is always findable.&lt;/p&gt;
&lt;p&gt;Contrast this with leverage: one engineer creates Bitcoin and generates billions in value. Another engineer writes code that goes unused despite identical hours invested. The inputs are the same. The outputs differ by orders of magnitude. Salary compresses this variance deliberately — your pay doesn’t fluctuate with actual impact. That’s comfortable, and it’s also the mechanism that makes wealth creation through employment alone structurally impossible.&lt;/p&gt;
&lt;h2 id=&quot;ownership-is-the-vehicle&quot;&gt;Ownership Is the Vehicle&lt;/h2&gt;
&lt;p&gt;The alternative is ownership — equity in something with productive potential. Stock options. Founding a company. Building something that generates returns without your continuous presence. Investing in assets.&lt;/p&gt;
&lt;p&gt;Naval is unambiguous: &lt;strong&gt;“You must own equity, a piece of a business, to gain your financial freedom.”&lt;/strong&gt; Not a higher salary. Not a better title. Equity — because equity is where upside is uncapped.&lt;/p&gt;
&lt;p&gt;A salary has a ceiling negotiated in advance. Equity reflects what the business actually creates. If the business generates disproportionate value, your ownership stake reflects that. The ceiling doesn’t exist.&lt;/p&gt;
&lt;p&gt;This doesn’t mean abandoning employment immediately. It means orienting every career decision toward increasing ownership of something — joining early-stage companies for equity rather than established ones for salary, building side projects with compounding potential, making investments. The vehicle matters as much as the effort.&lt;/p&gt;
&lt;h2 id=&quot;live-below-your-means--preserving-optionality&quot;&gt;Live Below Your Means — Preserving Optionality&lt;/h2&gt;
&lt;p&gt;There’s a companion principle: &lt;strong&gt;don’t inflate your lifestyle as your income rises&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Naval calls a monthly salary “one of the most dangerous drugs” — not because income is bad, but because predictable income trains you to spend up to it. As income rises, lifestyle expectations rise proportionally. The result is higher income with the same financial freedom — which is none. You’re running faster on a treadmill that also gets faster.&lt;/p&gt;
&lt;p&gt;The alternative pattern is making money in &lt;strong&gt;discrete lumps separated over long periods&lt;/strong&gt;, so your lifestyle baseline doesn’t have the chance to adapt. A founder who earns nothing for several years and then has a large exit hasn’t built the spending habits that a steadily rising salary would have created. They have optionality that a well-compensated employee — who spent every dollar as it arrived — doesn’t.&lt;/p&gt;
&lt;p&gt;Freedom comes from the gap between what you earn and what you spend. Closing that gap through consumption eliminates the resource that funds the ownership path in the first place.&lt;/p&gt;
&lt;h2 id=&quot;accountability-is-the-other-side-of-ownership&quot;&gt;Accountability Is the Other Side of Ownership&lt;/h2&gt;
&lt;p&gt;Ownership requires accountability — your name attached to outcomes, good or bad. This discomfort is why most people avoid it. The downside is visible and real.&lt;/p&gt;
&lt;p&gt;But accountability is also what makes ownership effective. When outcomes are tied to you specifically, you take the kind of care over your work that generates the best results. And it’s a market signal: founders with skin in the game attract better collaborators than those executing for a salary with no exposure to downside.&lt;/p&gt;
&lt;p&gt;The combination — equity ownership, accountability, specific skills, lifestyle below means — is what separates the wealth track from the income track. Each element enables the others.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Part 2 of 5. Read &lt;a href=&quot;/blog/how-to-get-rich-part-1-wealth-money-status/&quot;&gt;Part 1: Wealth, Money, and Status&lt;/a&gt; or continue to &lt;a href=&quot;/blog/how-to-get-rich-part-3-specific-knowledge/&quot;&gt;Part 3: Specific Knowledge Is Your Moat&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title>Wealth, Money, and Status: Getting the Definitions Right</title><link>https://abhimanyunagurkar.com/blog/how-to-get-rich-part-1-wealth-money-status/</link><guid isPermaLink="true">https://abhimanyunagurkar.com/blog/how-to-get-rich-part-1-wealth-money-status/</guid><description>Wealth, money, and status are three different things most people conflate. Naval Ravikant explains why the distinction changes everything.</description><pubDate>Sun, 03 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; This post is part of a personal learning series based on Naval Ravikant’s &lt;em&gt;“How to Get Rich”&lt;/em&gt; transcript, available at &lt;a href=&quot;https://nav.al/rich&quot;&gt;nav.al/rich&lt;/a&gt;. The ideas and frameworks here belong to Naval — I’m working through them for my own understanding. This is not financial advice.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;Most conversations about money collapse three distinct things into one word. Naval Ravikant’s framework starts by separating them cleanly, because until you define what you’re actually chasing, you can’t build a coherent strategy to get there.&lt;/p&gt;
&lt;h2 id=&quot;wealth-is-assets-that-earn-while-you-sleep&quot;&gt;Wealth Is Assets That Earn While You Sleep&lt;/h2&gt;
&lt;p&gt;Naval’s definition is precise: &lt;strong&gt;wealth is assets that earn while you sleep&lt;/strong&gt; — businesses, investments, intellectual property. Not your salary. Not your net worth as a number on a screen. Productive assets that generate returns independently of your time.&lt;/p&gt;
&lt;p&gt;This definition rules out money earned by showing up. It rules out status. It points exclusively at things that compound without your direct presence. A business you own that generates profit while you’re on holiday is wealth. A bonus you earned by working 80-hour weeks is not — you traded time for it once and it won’t repeat without more time.&lt;/p&gt;
&lt;p&gt;The goal behind wealth, in his framing, isn’t luxury. It’s freedom:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“So you don’t have to wear a tie like a collar around your neck. So you don’t have to wake up at 7:00 a.m. to rush to work.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sovereignty over your own time. That is the operative target.&lt;/p&gt;
&lt;h2 id=&quot;money-is-a-social-iou&quot;&gt;Money Is a Social IOU&lt;/h2&gt;
&lt;p&gt;Money is the transfer mechanism for wealth — a claim on human effort that can be redeemed for goods, services, or productive assets. When you earn a salary, you accumulate transferable claims on society. Spend them on consumption and they’re gone. Convert them into assets and they compound.&lt;/p&gt;
&lt;p&gt;The critical insight is that money is a means, not an end. People who confuse accumulating money with building wealth often end up with large account balances and no passive income. They have stored claims but nothing producing new ones.&lt;/p&gt;
&lt;h2 id=&quot;status-is-zero-sum&quot;&gt;Status Is Zero-Sum&lt;/h2&gt;
&lt;p&gt;Status is your rank within a social hierarchy. Unlike wealth, it is strictly zero-sum. For you to rise in status, someone else must fall. Every status point gained is, by definition, a status point lost by someone else.&lt;/p&gt;
&lt;p&gt;Wealth creation is the opposite — positive-sum. A software product built by one engineer can serve millions of people simultaneously. The engineer becomes wealthier, users get something useful, and no one loses anything in the exchange. Value was created, not redistributed.&lt;/p&gt;
&lt;p&gt;This distinction explains a real pattern: people who attack successful individuals are almost always playing status games, not engaging with economic reality. Dragging down someone wealthy does not make you wealthier. It moves someone lower in the hierarchy, which moves you up relatively. Naval is direct about this — it’s status-seeking disguised as moral positioning.&lt;/p&gt;
&lt;p&gt;Recognising the pattern means you can ignore the attacks. They’re irrelevant to building actual assets.&lt;/p&gt;
&lt;h2 id=&quot;ethical-wealth-creation-makes-the-world-better&quot;&gt;Ethical Wealth Creation Makes the World Better&lt;/h2&gt;
&lt;p&gt;Naval rejects the idea that wealth is extracted from others. Historical wealth creation — antibiotics, electricity, cars, smartphones — generated genuine abundance. The people who built those things got rich, and the world got better. Neither outcome was at the expense of the other.&lt;/p&gt;
&lt;p&gt;His thought experiment: if everyone had the engineering skills to build software and hardware, society would achieve enormous abundance with minimal required labour. Wealth creation at its core is building things that solve problems at scale. The builder captures a fraction of the value generated for others; the rest belongs to the world.&lt;/p&gt;
&lt;p&gt;The corollary is what happens when the balance tips. When takers outnumber makers, productive capacity shrinks and systems deteriorate — not because wealth is unfair, but because the incentive to create disappears.&lt;/p&gt;
&lt;h2 id=&quot;free-markets-emerge-from-human-nature&quot;&gt;Free Markets Emerge From Human Nature&lt;/h2&gt;
&lt;p&gt;Naval argues that voluntary exchange and credit-debit tracking are evolutionary traits, not political inventions. Humans uniquely cooperate across genetic lines — we form relationships, track obligations, and trade with strangers because we developed the capacity to maintain mental ledgers of who owes what to whom.&lt;/p&gt;
&lt;p&gt;Markets formalise this instinct. The mechanism by which billions of people coordinate effort and allocate resources without central direction is not a social construct imposed from above — it’s the formalisation of something humans already do naturally.&lt;/p&gt;
&lt;h2 id=&quot;what-this-means-in-practice&quot;&gt;What This Means in Practice&lt;/h2&gt;
&lt;p&gt;Before building any strategy, it helps to be clear about what you’re actually trying to build:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Wealth&lt;/strong&gt; — assets earning independently of your time. The actual goal.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Money&lt;/strong&gt; — the transfer medium. Useful, but transient unless converted into assets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Status&lt;/strong&gt; — social hierarchy rank. Zero-sum, mostly irrelevant to financial freedom.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The game worth playing is wealth creation. Misaligning on these definitions leads to building the wrong things — engineers optimising for prestigious titles instead of equity, founders chasing recognition instead of revenue, professionals maximising salary instead of ownership. All of them are playing a version of the status game while believing they’re on the wealth track.&lt;/p&gt;
&lt;p&gt;The framework starts here because everything else — leverage, specific knowledge, long-term games — only works if the target is right.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;This is Part 1 of 5. Continue with &lt;a href=&quot;/blog/how-to-get-rich-part-2-luck-you-can-engineer/&quot;&gt;Part 2: The Luck You Can Engineer&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title>B-Trees and B+ Trees: From Binary Trees to Database Indexes</title><link>https://abhimanyunagurkar.com/blog/btrees-and-bplus-trees/</link><guid isPermaLink="true">https://abhimanyunagurkar.com/blog/btrees-and-bplus-trees/</guid><description>If you know binary search trees, you are halfway to understanding how databases find your data. B-trees are BSTs that got wide on purpose — here is why.</description><pubDate>Sat, 02 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;You already understand binary search trees. Each node has one key, two children, the left subtree is always smaller, the right always larger. For a tree with a million nodes, you find any key in about 20 comparisons.&lt;/p&gt;
&lt;p&gt;That sounds fast. At in-memory speeds it is. At disk speeds, it kills you.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;why-bsts-break-at-disk-scale&quot;&gt;Why BSTs Break at Disk Scale&lt;/h2&gt;
&lt;p&gt;Every time you descend a level in a BST, you are potentially reading from a different location on disk. In RAM, that is a cache miss — nanoseconds. On a spinning disk, that is a random seek (a seek is the disk arm physically moving to a new track on a hard drive) — milliseconds. A million-node BST has ~20 levels. Twenty disk reads per query. At 5ms per seek, that is 100ms before you return a single row.&lt;/p&gt;
&lt;p&gt;A &lt;em&gt;page&lt;/em&gt; is the fixed-size block (typically 4–16 KB) that databases read from disk in a single I/O — we’ll see why this matters in a moment.&lt;/p&gt;
&lt;p&gt;The fix is not to speed up disk. The fix is to read fewer levels.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If each node could hold 1,000 keys instead of 1, the tree would be 1,000x shallower.&lt;/strong&gt; A million-row table needs only 2 levels. A billion-row table needs 3.&lt;/p&gt;
&lt;p&gt;That is the entire idea behind B-trees.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;b-trees-bsts-gone-wide&quot;&gt;B-Trees: BSTs Gone Wide&lt;/h2&gt;
&lt;p&gt;A B-tree generalizes the BST by allowing each node to hold many keys and have many children. The sorted invariant is identical — it just applies across more keys per node.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Formal rules for a B-tree of order &lt;code&gt;t&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Each node holds between &lt;code&gt;t-1&lt;/code&gt; and &lt;code&gt;2t-1&lt;/code&gt; keys (the root can have as few as 1)&lt;/li&gt;
&lt;li&gt;Each internal node has exactly one more child than it has keys&lt;/li&gt;
&lt;li&gt;All leaves sit at the same depth — always&lt;/li&gt;
&lt;li&gt;Keys within a node are sorted ascending&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here &lt;code&gt;t&lt;/code&gt; is the tree’s &lt;em&gt;minimum degree&lt;/em&gt; — the lower bound on keys per node. The branching factor (children per internal node) is up to &lt;code&gt;2t&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For &lt;code&gt;t=2&lt;/code&gt; (the smallest B-tree allowed by the definition, also called a 2-3-4 tree), each node holds 1 to 3 keys and has 2 to 4 children.&lt;/p&gt;
&lt;p&gt;Here is what a B-tree of order &lt;code&gt;t=2&lt;/code&gt; looks like:&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 466 282&quot;&gt;&lt;svg class=&quot;d2-2853755416 d2-svg&quot; width=&quot;466&quot; height=&quot;282&quot; viewBox=&quot;-25 -25 466 282&quot;&gt;&lt;rect x=&quot;-25.000000&quot; y=&quot;-25.000000&quot; width=&quot;466.000000&quot; height=&quot;282.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-2853755416 .text-bold {
	font-family: &quot;d2-2853755416-font-bold&quot;;
}
@font-face {
	font-family: d2-2853755416-font-bold;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-2853755416 .fill-N1{fill:#0A0F25;}
		.d2-2853755416 .fill-N2{fill:#676C7E;}
		.d2-2853755416 .fill-N3{fill:#9499AB;}
		.d2-2853755416 .fill-N4{fill:#CFD2DD;}
		.d2-2853755416 .fill-N5{fill:#DEE1EB;}
		.d2-2853755416 .fill-N6{fill:#EEF1F8;}
		.d2-2853755416 .fill-N7{fill:#FFFFFF;}
		.d2-2853755416 .fill-B1{fill:#0D32B2;}
		.d2-2853755416 .fill-B2{fill:#0D32B2;}
		.d2-2853755416 .fill-B3{fill:#E3E9FD;}
		.d2-2853755416 .fill-B4{fill:#E3E9FD;}
		.d2-2853755416 .fill-B5{fill:#EDF0FD;}
		.d2-2853755416 .fill-B6{fill:#F7F8FE;}
		.d2-2853755416 .fill-AA2{fill:#4A6FF3;}
		.d2-2853755416 .fill-AA4{fill:#EDF0FD;}
		.d2-2853755416 .fill-AA5{fill:#F7F8FE;}
		.d2-2853755416 .fill-AB4{fill:#EDF0FD;}
		.d2-2853755416 .fill-AB5{fill:#F7F8FE;}
		.d2-2853755416 .stroke-N1{stroke:#0A0F25;}
		.d2-2853755416 .stroke-N2{stroke:#676C7E;}
		.d2-2853755416 .stroke-N3{stroke:#9499AB;}
		.d2-2853755416 .stroke-N4{stroke:#CFD2DD;}
		.d2-2853755416 .stroke-N5{stroke:#DEE1EB;}
		.d2-2853755416 .stroke-N6{stroke:#EEF1F8;}
		.d2-2853755416 .stroke-N7{stroke:#FFFFFF;}
		.d2-2853755416 .stroke-B1{stroke:#0D32B2;}
		.d2-2853755416 .stroke-B2{stroke:#0D32B2;}
		.d2-2853755416 .stroke-B3{stroke:#E3E9FD;}
		.d2-2853755416 .stroke-B4{stroke:#E3E9FD;}
		.d2-2853755416 .stroke-B5{stroke:#EDF0FD;}
		.d2-2853755416 .stroke-B6{stroke:#F7F8FE;}
		.d2-2853755416 .stroke-AA2{stroke:#4A6FF3;}
		.d2-2853755416 .stroke-AA4{stroke:#EDF0FD;}
		.d2-2853755416 .stroke-AA5{stroke:#F7F8FE;}
		.d2-2853755416 .stroke-AB4{stroke:#EDF0FD;}
		.d2-2853755416 .stroke-AB5{stroke:#F7F8FE;}
		.d2-2853755416 .background-color-N1{background-color:#0A0F25;}
		.d2-2853755416 .background-color-N2{background-color:#676C7E;}
		.d2-2853755416 .background-color-N3{background-color:#9499AB;}
		.d2-2853755416 .background-color-N4{background-color:#CFD2DD;}
		.d2-2853755416 .background-color-N5{background-color:#DEE1EB;}
		.d2-2853755416 .background-color-N6{background-color:#EEF1F8;}
		.d2-2853755416 .background-color-N7{background-color:#FFFFFF;}
		.d2-2853755416 .background-color-B1{background-color:#0D32B2;}
		.d2-2853755416 .background-color-B2{background-color:#0D32B2;}
		.d2-2853755416 .background-color-B3{background-color:#E3E9FD;}
		.d2-2853755416 .background-color-B4{background-color:#E3E9FD;}
		.d2-2853755416 .background-color-B5{background-color:#EDF0FD;}
		.d2-2853755416 .background-color-B6{background-color:#F7F8FE;}
		.d2-2853755416 .background-color-AA2{background-color:#4A6FF3;}
		.d2-2853755416 .background-color-AA4{background-color:#EDF0FD;}
		.d2-2853755416 .background-color-AA5{background-color:#F7F8FE;}
		.d2-2853755416 .background-color-AB4{background-color:#EDF0FD;}
		.d2-2853755416 .background-color-AB5{background-color:#F7F8FE;}
		.d2-2853755416 .color-N1{color:#0A0F25;}
		.d2-2853755416 .color-N2{color:#676C7E;}
		.d2-2853755416 .color-N3{color:#9499AB;}
		.d2-2853755416 .color-N4{color:#CFD2DD;}
		.d2-2853755416 .color-N5{color:#DEE1EB;}
		.d2-2853755416 .color-N6{color:#EEF1F8;}
		.d2-2853755416 .color-N7{color:#FFFFFF;}
		.d2-2853755416 .color-B1{color:#0D32B2;}
		.d2-2853755416 .color-B2{color:#0D32B2;}
		.d2-2853755416 .color-B3{color:#E3E9FD;}
		.d2-2853755416 .color-B4{color:#E3E9FD;}
		.d2-2853755416 .color-B5{color:#EDF0FD;}
		.d2-2853755416 .color-B6{color:#F7F8FE;}
		.d2-2853755416 .color-AA2{color:#4A6FF3;}
		.d2-2853755416 .color-AA4{color:#EDF0FD;}
		.d2-2853755416 .color-AA5{color:#F7F8FE;}
		.d2-2853755416 .color-AB4{color:#EDF0FD;}
		.d2-2853755416 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-2853755416);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-2853755416);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-2853755416);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-2853755416);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-2853755416);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-2853755416);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-2853755416);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-2853755416);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-2853755416);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-2853755416);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-2853755416);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-2853755416);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-2853755416);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-2853755416);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-2853755416);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-2853755416);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-2853755416);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-2853755416);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;cm9vdA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;163.000000&quot; y=&quot;0.000000&quot; width=&quot;90.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;208.000000&quot; y=&quot;38.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;30 | 70&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;bjE=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;0.000000&quot; y=&quot;166.000000&quot; width=&quot;89.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;44.500000&quot; y=&quot;204.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;10 | 20&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;bjI=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;149.000000&quot; y=&quot;166.000000&quot; width=&quot;117.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;207.500000&quot; y=&quot;204.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;40 | 50 | 60&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;bjM=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;326.000000&quot; y=&quot;166.000000&quot; width=&quot;90.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;371.000000&quot; y=&quot;204.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;80 | 90&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KHJvb3QgLSZndDsgbjEpWzBd&quot;&gt;&lt;marker id=&quot;mk-d2-2853755416-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 160.717749 56.821515 C 68.099998 103.982002 44.500000 126.000000 44.500000 162.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-2853755416-3488378134)&quot; mask=&quot;url(#d2-2853755416)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KHJvb3QgLSZndDsgbjIpWzBd&quot;&gt;&lt;path d=&quot;M 207.500000 68.000000 C 207.500000 106.000000 207.500000 126.000000 207.500000 162.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-2853755416-3488378134)&quot; mask=&quot;url(#d2-2853755416)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KHJvb3QgLSZndDsgbjMpWzBd&quot;&gt;&lt;path d=&quot;M 254.782770 56.906493 C 347.399994 104.000000 371.000000 126.000000 371.000000 162.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-2853755416-3488378134)&quot; mask=&quot;url(#d2-2853755416)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;mask id=&quot;d2-2853755416&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;466&quot; height=&quot;282&quot;&gt;
&lt;rect x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;466&quot; height=&quot;282&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;

&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;The same BST invariant holds: every key in &lt;code&gt;n1&lt;/code&gt; is less than 30, every key in &lt;code&gt;n2&lt;/code&gt; is between 30 and 70, every key in &lt;code&gt;n3&lt;/code&gt; is greater than 70. It is just a wider tree.&lt;/p&gt;
&lt;p&gt;In a B-tree, &lt;strong&gt;internal nodes store both keys and the actual data values&lt;/strong&gt;. You can hit your target at any level of the tree.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;search-same-idea-wider-nodes&quot;&gt;Search: Same Idea, Wider Nodes&lt;/h2&gt;
&lt;p&gt;Search works identically to a BST. At each node, scan the keys left-to-right to find which child to follow (or return if you find the key directly).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Find key 50:&lt;/strong&gt;&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 466 282&quot;&gt;&lt;svg class=&quot;d2-2853755416 d2-svg&quot; width=&quot;466&quot; height=&quot;282&quot; viewBox=&quot;-25 -25 466 282&quot;&gt;&lt;rect x=&quot;-25.000000&quot; y=&quot;-25.000000&quot; width=&quot;466.000000&quot; height=&quot;282.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-2853755416 .text-bold {
	font-family: &quot;d2-2853755416-font-bold&quot;;
}
@font-face {
	font-family: d2-2853755416-font-bold;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-2853755416 .fill-N1{fill:#0A0F25;}
		.d2-2853755416 .fill-N2{fill:#676C7E;}
		.d2-2853755416 .fill-N3{fill:#9499AB;}
		.d2-2853755416 .fill-N4{fill:#CFD2DD;}
		.d2-2853755416 .fill-N5{fill:#DEE1EB;}
		.d2-2853755416 .fill-N6{fill:#EEF1F8;}
		.d2-2853755416 .fill-N7{fill:#FFFFFF;}
		.d2-2853755416 .fill-B1{fill:#0D32B2;}
		.d2-2853755416 .fill-B2{fill:#0D32B2;}
		.d2-2853755416 .fill-B3{fill:#E3E9FD;}
		.d2-2853755416 .fill-B4{fill:#E3E9FD;}
		.d2-2853755416 .fill-B5{fill:#EDF0FD;}
		.d2-2853755416 .fill-B6{fill:#F7F8FE;}
		.d2-2853755416 .fill-AA2{fill:#4A6FF3;}
		.d2-2853755416 .fill-AA4{fill:#EDF0FD;}
		.d2-2853755416 .fill-AA5{fill:#F7F8FE;}
		.d2-2853755416 .fill-AB4{fill:#EDF0FD;}
		.d2-2853755416 .fill-AB5{fill:#F7F8FE;}
		.d2-2853755416 .stroke-N1{stroke:#0A0F25;}
		.d2-2853755416 .stroke-N2{stroke:#676C7E;}
		.d2-2853755416 .stroke-N3{stroke:#9499AB;}
		.d2-2853755416 .stroke-N4{stroke:#CFD2DD;}
		.d2-2853755416 .stroke-N5{stroke:#DEE1EB;}
		.d2-2853755416 .stroke-N6{stroke:#EEF1F8;}
		.d2-2853755416 .stroke-N7{stroke:#FFFFFF;}
		.d2-2853755416 .stroke-B1{stroke:#0D32B2;}
		.d2-2853755416 .stroke-B2{stroke:#0D32B2;}
		.d2-2853755416 .stroke-B3{stroke:#E3E9FD;}
		.d2-2853755416 .stroke-B4{stroke:#E3E9FD;}
		.d2-2853755416 .stroke-B5{stroke:#EDF0FD;}
		.d2-2853755416 .stroke-B6{stroke:#F7F8FE;}
		.d2-2853755416 .stroke-AA2{stroke:#4A6FF3;}
		.d2-2853755416 .stroke-AA4{stroke:#EDF0FD;}
		.d2-2853755416 .stroke-AA5{stroke:#F7F8FE;}
		.d2-2853755416 .stroke-AB4{stroke:#EDF0FD;}
		.d2-2853755416 .stroke-AB5{stroke:#F7F8FE;}
		.d2-2853755416 .background-color-N1{background-color:#0A0F25;}
		.d2-2853755416 .background-color-N2{background-color:#676C7E;}
		.d2-2853755416 .background-color-N3{background-color:#9499AB;}
		.d2-2853755416 .background-color-N4{background-color:#CFD2DD;}
		.d2-2853755416 .background-color-N5{background-color:#DEE1EB;}
		.d2-2853755416 .background-color-N6{background-color:#EEF1F8;}
		.d2-2853755416 .background-color-N7{background-color:#FFFFFF;}
		.d2-2853755416 .background-color-B1{background-color:#0D32B2;}
		.d2-2853755416 .background-color-B2{background-color:#0D32B2;}
		.d2-2853755416 .background-color-B3{background-color:#E3E9FD;}
		.d2-2853755416 .background-color-B4{background-color:#E3E9FD;}
		.d2-2853755416 .background-color-B5{background-color:#EDF0FD;}
		.d2-2853755416 .background-color-B6{background-color:#F7F8FE;}
		.d2-2853755416 .background-color-AA2{background-color:#4A6FF3;}
		.d2-2853755416 .background-color-AA4{background-color:#EDF0FD;}
		.d2-2853755416 .background-color-AA5{background-color:#F7F8FE;}
		.d2-2853755416 .background-color-AB4{background-color:#EDF0FD;}
		.d2-2853755416 .background-color-AB5{background-color:#F7F8FE;}
		.d2-2853755416 .color-N1{color:#0A0F25;}
		.d2-2853755416 .color-N2{color:#676C7E;}
		.d2-2853755416 .color-N3{color:#9499AB;}
		.d2-2853755416 .color-N4{color:#CFD2DD;}
		.d2-2853755416 .color-N5{color:#DEE1EB;}
		.d2-2853755416 .color-N6{color:#EEF1F8;}
		.d2-2853755416 .color-N7{color:#FFFFFF;}
		.d2-2853755416 .color-B1{color:#0D32B2;}
		.d2-2853755416 .color-B2{color:#0D32B2;}
		.d2-2853755416 .color-B3{color:#E3E9FD;}
		.d2-2853755416 .color-B4{color:#E3E9FD;}
		.d2-2853755416 .color-B5{color:#EDF0FD;}
		.d2-2853755416 .color-B6{color:#F7F8FE;}
		.d2-2853755416 .color-AA2{color:#4A6FF3;}
		.d2-2853755416 .color-AA4{color:#EDF0FD;}
		.d2-2853755416 .color-AA5{color:#F7F8FE;}
		.d2-2853755416 .color-AB4{color:#EDF0FD;}
		.d2-2853755416 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-2853755416);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-2853755416);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-2853755416);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-2853755416);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-2853755416);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-2853755416);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-2853755416);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-2853755416);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-2853755416);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-2853755416);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-2853755416);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-2853755416);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-2853755416);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-2853755416);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-2853755416);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-2853755416);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-2853755416);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-2853755416);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;cm9vdA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;163.000000&quot; y=&quot;0.000000&quot; width=&quot;90.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;208.000000&quot; y=&quot;38.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;30 | 70&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;bjE=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;0.000000&quot; y=&quot;166.000000&quot; width=&quot;89.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;44.500000&quot; y=&quot;204.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;10 | 20&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;bjI=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;149.000000&quot; y=&quot;166.000000&quot; width=&quot;117.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;207.500000&quot; y=&quot;204.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;40 | 50 | 60&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;bjM=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;326.000000&quot; y=&quot;166.000000&quot; width=&quot;90.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;371.000000&quot; y=&quot;204.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;80 | 90&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KHJvb3QgLSZndDsgbjEpWzBd&quot;&gt;&lt;marker id=&quot;mk-d2-2853755416-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 160.717749 56.821515 C 68.099998 103.982002 44.500000 126.000000 44.500000 162.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-2853755416-3488378134)&quot; mask=&quot;url(#d2-2853755416)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KHJvb3QgLSZndDsgbjIpWzBd&quot;&gt;&lt;path d=&quot;M 207.500000 68.000000 C 207.500000 106.000000 207.500000 126.000000 207.500000 162.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-2853755416-3488378134)&quot; mask=&quot;url(#d2-2853755416)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KHJvb3QgLSZndDsgbjMpWzBd&quot;&gt;&lt;path d=&quot;M 254.782770 56.906493 C 347.399994 104.000000 371.000000 126.000000 371.000000 162.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-2853755416-3488378134)&quot; mask=&quot;url(#d2-2853755416)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;mask id=&quot;d2-2853755416&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;466&quot; height=&quot;282&quot;&gt;
&lt;rect x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;466&quot; height=&quot;282&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;

&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;ol&gt;
&lt;li&gt;At root &lt;code&gt;[30 | 70]&lt;/code&gt;: 50 &gt; 30 and 50 &amp;#x3C; 70 → take middle child&lt;/li&gt;
&lt;li&gt;At &lt;code&gt;[40 | 50 | 60]&lt;/code&gt;: scan left to right, find 50 → return value&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Two disk reads. In a BST of 9 nodes that is also two reads — but the B-tree scales to millions of nodes while still needing only 2–3 reads. The branching factor is the lever.&lt;/p&gt;
&lt;p&gt;The per-node scan is O(t) (or O(log t) with binary search), and tree height is O(log of n in base t) — so total work simplifies to O(log n) since t is a constant for any given database. The win is entirely in the constant — fewer levels means fewer disk reads.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;insertion-splits-keep-the-tree-balanced&quot;&gt;Insertion: Splits Keep the Tree Balanced&lt;/h2&gt;
&lt;p&gt;You always insert at a &lt;strong&gt;leaf&lt;/strong&gt;. Walk down using the same search logic, land at the right leaf, insert the key in sorted position.&lt;/p&gt;
&lt;p&gt;The problem: a leaf can overflow — it may already have &lt;code&gt;2t-1&lt;/code&gt; keys (the maximum). The fix is to &lt;strong&gt;split&lt;/strong&gt; the overfull node before inserting into it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Splitting&lt;/strong&gt; takes a full node with &lt;code&gt;2t-1&lt;/code&gt; keys and produces:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A left child with the first &lt;code&gt;t-1&lt;/code&gt; keys&lt;/li&gt;
&lt;li&gt;A right child with the last &lt;code&gt;t-1&lt;/code&gt; keys&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;middle key&lt;/strong&gt;, which is promoted up to the parent&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Example: insert 55. The right child is full and must be split first.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before:&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 316 282&quot;&gt;&lt;svg class=&quot;d2-3171451359 d2-svg&quot; width=&quot;316&quot; height=&quot;282&quot; viewBox=&quot;-25 -25 316 282&quot;&gt;&lt;rect x=&quot;-25.000000&quot; y=&quot;-25.000000&quot; width=&quot;316.000000&quot; height=&quot;282.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-3171451359 .text-bold {
	font-family: &quot;d2-3171451359-font-bold&quot;;
}
@font-face {
	font-family: d2-3171451359-font-bold;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-3171451359 .fill-N1{fill:#0A0F25;}
		.d2-3171451359 .fill-N2{fill:#676C7E;}
		.d2-3171451359 .fill-N3{fill:#9499AB;}
		.d2-3171451359 .fill-N4{fill:#CFD2DD;}
		.d2-3171451359 .fill-N5{fill:#DEE1EB;}
		.d2-3171451359 .fill-N6{fill:#EEF1F8;}
		.d2-3171451359 .fill-N7{fill:#FFFFFF;}
		.d2-3171451359 .fill-B1{fill:#0D32B2;}
		.d2-3171451359 .fill-B2{fill:#0D32B2;}
		.d2-3171451359 .fill-B3{fill:#E3E9FD;}
		.d2-3171451359 .fill-B4{fill:#E3E9FD;}
		.d2-3171451359 .fill-B5{fill:#EDF0FD;}
		.d2-3171451359 .fill-B6{fill:#F7F8FE;}
		.d2-3171451359 .fill-AA2{fill:#4A6FF3;}
		.d2-3171451359 .fill-AA4{fill:#EDF0FD;}
		.d2-3171451359 .fill-AA5{fill:#F7F8FE;}
		.d2-3171451359 .fill-AB4{fill:#EDF0FD;}
		.d2-3171451359 .fill-AB5{fill:#F7F8FE;}
		.d2-3171451359 .stroke-N1{stroke:#0A0F25;}
		.d2-3171451359 .stroke-N2{stroke:#676C7E;}
		.d2-3171451359 .stroke-N3{stroke:#9499AB;}
		.d2-3171451359 .stroke-N4{stroke:#CFD2DD;}
		.d2-3171451359 .stroke-N5{stroke:#DEE1EB;}
		.d2-3171451359 .stroke-N6{stroke:#EEF1F8;}
		.d2-3171451359 .stroke-N7{stroke:#FFFFFF;}
		.d2-3171451359 .stroke-B1{stroke:#0D32B2;}
		.d2-3171451359 .stroke-B2{stroke:#0D32B2;}
		.d2-3171451359 .stroke-B3{stroke:#E3E9FD;}
		.d2-3171451359 .stroke-B4{stroke:#E3E9FD;}
		.d2-3171451359 .stroke-B5{stroke:#EDF0FD;}
		.d2-3171451359 .stroke-B6{stroke:#F7F8FE;}
		.d2-3171451359 .stroke-AA2{stroke:#4A6FF3;}
		.d2-3171451359 .stroke-AA4{stroke:#EDF0FD;}
		.d2-3171451359 .stroke-AA5{stroke:#F7F8FE;}
		.d2-3171451359 .stroke-AB4{stroke:#EDF0FD;}
		.d2-3171451359 .stroke-AB5{stroke:#F7F8FE;}
		.d2-3171451359 .background-color-N1{background-color:#0A0F25;}
		.d2-3171451359 .background-color-N2{background-color:#676C7E;}
		.d2-3171451359 .background-color-N3{background-color:#9499AB;}
		.d2-3171451359 .background-color-N4{background-color:#CFD2DD;}
		.d2-3171451359 .background-color-N5{background-color:#DEE1EB;}
		.d2-3171451359 .background-color-N6{background-color:#EEF1F8;}
		.d2-3171451359 .background-color-N7{background-color:#FFFFFF;}
		.d2-3171451359 .background-color-B1{background-color:#0D32B2;}
		.d2-3171451359 .background-color-B2{background-color:#0D32B2;}
		.d2-3171451359 .background-color-B3{background-color:#E3E9FD;}
		.d2-3171451359 .background-color-B4{background-color:#E3E9FD;}
		.d2-3171451359 .background-color-B5{background-color:#EDF0FD;}
		.d2-3171451359 .background-color-B6{background-color:#F7F8FE;}
		.d2-3171451359 .background-color-AA2{background-color:#4A6FF3;}
		.d2-3171451359 .background-color-AA4{background-color:#EDF0FD;}
		.d2-3171451359 .background-color-AA5{background-color:#F7F8FE;}
		.d2-3171451359 .background-color-AB4{background-color:#EDF0FD;}
		.d2-3171451359 .background-color-AB5{background-color:#F7F8FE;}
		.d2-3171451359 .color-N1{color:#0A0F25;}
		.d2-3171451359 .color-N2{color:#676C7E;}
		.d2-3171451359 .color-N3{color:#9499AB;}
		.d2-3171451359 .color-N4{color:#CFD2DD;}
		.d2-3171451359 .color-N5{color:#DEE1EB;}
		.d2-3171451359 .color-N6{color:#EEF1F8;}
		.d2-3171451359 .color-N7{color:#FFFFFF;}
		.d2-3171451359 .color-B1{color:#0D32B2;}
		.d2-3171451359 .color-B2{color:#0D32B2;}
		.d2-3171451359 .color-B3{color:#E3E9FD;}
		.d2-3171451359 .color-B4{color:#E3E9FD;}
		.d2-3171451359 .color-B5{color:#EDF0FD;}
		.d2-3171451359 .color-B6{color:#F7F8FE;}
		.d2-3171451359 .color-AA2{color:#4A6FF3;}
		.d2-3171451359 .color-AA4{color:#EDF0FD;}
		.d2-3171451359 .color-AA5{color:#F7F8FE;}
		.d2-3171451359 .color-AB4{color:#EDF0FD;}
		.d2-3171451359 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-3171451359);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-3171451359);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-3171451359);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-3171451359);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-3171451359);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-3171451359);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-3171451359);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-3171451359);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-3171451359);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-3171451359);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-3171451359);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-3171451359);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-3171451359);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-3171451359);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-3171451359);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-3171451359);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-3171451359);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-3171451359);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;cm9vdA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;95.000000&quot; y=&quot;0.000000&quot; width=&quot;62.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;126.000000&quot; y=&quot;38.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;30&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;bA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;0.000000&quot; y=&quot;166.000000&quot; width=&quot;89.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;44.500000&quot; y=&quot;204.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;10 | 20&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;cg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;149.000000&quot; y=&quot;166.000000&quot; width=&quot;117.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;207.500000&quot; y=&quot;204.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;40 | 50 | 60&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KHJvb3QgLSZndDsgbClbMF0=&quot;&gt;&lt;marker id=&quot;mk-d2-3171451359-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 94.085769 66.414196 C 54.699001 105.800003 44.500000 126.000000 44.500000 162.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3171451359-3488378134)&quot; mask=&quot;url(#d2-3171451359)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KHJvb3QgLSZndDsgcilbMF0=&quot;&gt;&lt;path d=&quot;M 157.914214 66.414214 C 197.300003 105.800003 207.500000 126.000000 207.500000 162.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3171451359-3488378134)&quot; mask=&quot;url(#d2-3171451359)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;mask id=&quot;d2-3171451359&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;316&quot; height=&quot;282&quot;&gt;
&lt;rect x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;316&quot; height=&quot;282&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;

&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;Split &lt;code&gt;[40 | 50 | 60]&lt;/code&gt;. Middle key 50 is promoted to the parent:&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 383 282&quot;&gt;&lt;svg class=&quot;d2-1733649538 d2-svg&quot; width=&quot;383&quot; height=&quot;282&quot; viewBox=&quot;-25 -25 383 282&quot;&gt;&lt;rect x=&quot;-25.000000&quot; y=&quot;-25.000000&quot; width=&quot;383.000000&quot; height=&quot;282.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-1733649538 .text-bold {
	font-family: &quot;d2-1733649538-font-bold&quot;;
}
@font-face {
	font-family: d2-1733649538-font-bold;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-1733649538 .fill-N1{fill:#0A0F25;}
		.d2-1733649538 .fill-N2{fill:#676C7E;}
		.d2-1733649538 .fill-N3{fill:#9499AB;}
		.d2-1733649538 .fill-N4{fill:#CFD2DD;}
		.d2-1733649538 .fill-N5{fill:#DEE1EB;}
		.d2-1733649538 .fill-N6{fill:#EEF1F8;}
		.d2-1733649538 .fill-N7{fill:#FFFFFF;}
		.d2-1733649538 .fill-B1{fill:#0D32B2;}
		.d2-1733649538 .fill-B2{fill:#0D32B2;}
		.d2-1733649538 .fill-B3{fill:#E3E9FD;}
		.d2-1733649538 .fill-B4{fill:#E3E9FD;}
		.d2-1733649538 .fill-B5{fill:#EDF0FD;}
		.d2-1733649538 .fill-B6{fill:#F7F8FE;}
		.d2-1733649538 .fill-AA2{fill:#4A6FF3;}
		.d2-1733649538 .fill-AA4{fill:#EDF0FD;}
		.d2-1733649538 .fill-AA5{fill:#F7F8FE;}
		.d2-1733649538 .fill-AB4{fill:#EDF0FD;}
		.d2-1733649538 .fill-AB5{fill:#F7F8FE;}
		.d2-1733649538 .stroke-N1{stroke:#0A0F25;}
		.d2-1733649538 .stroke-N2{stroke:#676C7E;}
		.d2-1733649538 .stroke-N3{stroke:#9499AB;}
		.d2-1733649538 .stroke-N4{stroke:#CFD2DD;}
		.d2-1733649538 .stroke-N5{stroke:#DEE1EB;}
		.d2-1733649538 .stroke-N6{stroke:#EEF1F8;}
		.d2-1733649538 .stroke-N7{stroke:#FFFFFF;}
		.d2-1733649538 .stroke-B1{stroke:#0D32B2;}
		.d2-1733649538 .stroke-B2{stroke:#0D32B2;}
		.d2-1733649538 .stroke-B3{stroke:#E3E9FD;}
		.d2-1733649538 .stroke-B4{stroke:#E3E9FD;}
		.d2-1733649538 .stroke-B5{stroke:#EDF0FD;}
		.d2-1733649538 .stroke-B6{stroke:#F7F8FE;}
		.d2-1733649538 .stroke-AA2{stroke:#4A6FF3;}
		.d2-1733649538 .stroke-AA4{stroke:#EDF0FD;}
		.d2-1733649538 .stroke-AA5{stroke:#F7F8FE;}
		.d2-1733649538 .stroke-AB4{stroke:#EDF0FD;}
		.d2-1733649538 .stroke-AB5{stroke:#F7F8FE;}
		.d2-1733649538 .background-color-N1{background-color:#0A0F25;}
		.d2-1733649538 .background-color-N2{background-color:#676C7E;}
		.d2-1733649538 .background-color-N3{background-color:#9499AB;}
		.d2-1733649538 .background-color-N4{background-color:#CFD2DD;}
		.d2-1733649538 .background-color-N5{background-color:#DEE1EB;}
		.d2-1733649538 .background-color-N6{background-color:#EEF1F8;}
		.d2-1733649538 .background-color-N7{background-color:#FFFFFF;}
		.d2-1733649538 .background-color-B1{background-color:#0D32B2;}
		.d2-1733649538 .background-color-B2{background-color:#0D32B2;}
		.d2-1733649538 .background-color-B3{background-color:#E3E9FD;}
		.d2-1733649538 .background-color-B4{background-color:#E3E9FD;}
		.d2-1733649538 .background-color-B5{background-color:#EDF0FD;}
		.d2-1733649538 .background-color-B6{background-color:#F7F8FE;}
		.d2-1733649538 .background-color-AA2{background-color:#4A6FF3;}
		.d2-1733649538 .background-color-AA4{background-color:#EDF0FD;}
		.d2-1733649538 .background-color-AA5{background-color:#F7F8FE;}
		.d2-1733649538 .background-color-AB4{background-color:#EDF0FD;}
		.d2-1733649538 .background-color-AB5{background-color:#F7F8FE;}
		.d2-1733649538 .color-N1{color:#0A0F25;}
		.d2-1733649538 .color-N2{color:#676C7E;}
		.d2-1733649538 .color-N3{color:#9499AB;}
		.d2-1733649538 .color-N4{color:#CFD2DD;}
		.d2-1733649538 .color-N5{color:#DEE1EB;}
		.d2-1733649538 .color-N6{color:#EEF1F8;}
		.d2-1733649538 .color-N7{color:#FFFFFF;}
		.d2-1733649538 .color-B1{color:#0D32B2;}
		.d2-1733649538 .color-B2{color:#0D32B2;}
		.d2-1733649538 .color-B3{color:#E3E9FD;}
		.d2-1733649538 .color-B4{color:#E3E9FD;}
		.d2-1733649538 .color-B5{color:#EDF0FD;}
		.d2-1733649538 .color-B6{color:#F7F8FE;}
		.d2-1733649538 .color-AA2{color:#4A6FF3;}
		.d2-1733649538 .color-AA4{color:#EDF0FD;}
		.d2-1733649538 .color-AA5{color:#F7F8FE;}
		.d2-1733649538 .color-AB4{color:#EDF0FD;}
		.d2-1733649538 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-1733649538);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-1733649538);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-1733649538);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-1733649538);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-1733649538);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-1733649538);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-1733649538);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-1733649538);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-1733649538);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-1733649538);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-1733649538);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-1733649538);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-1733649538);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-1733649538);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-1733649538);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-1733649538);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-1733649538);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-1733649538);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;cm9vdA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;135.000000&quot; y=&quot;0.000000&quot; width=&quot;90.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;180.000000&quot; y=&quot;38.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;30 | 50&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;bA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;0.000000&quot; y=&quot;166.000000&quot; width=&quot;89.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;44.500000&quot; y=&quot;204.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;10 | 20&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;bQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;149.000000&quot; y=&quot;166.000000&quot; width=&quot;62.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;180.000000&quot; y=&quot;204.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;40&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;cg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;271.000000&quot; y=&quot;166.000000&quot; width=&quot;62.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;302.000000&quot; y=&quot;204.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;60&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KHJvb3QgLSZndDsgbClbMF0=&quot;&gt;&lt;marker id=&quot;mk-d2-1733649538-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 133.788342 62.034518 C 62.700001 105.000000 44.500000 126.000000 44.500000 162.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1733649538-3488378134)&quot; mask=&quot;url(#d2-1733649538)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KHJvb3QgLSZndDsgbSlbMF0=&quot;&gt;&lt;path d=&quot;M 180.000000 68.000000 C 180.000000 106.000000 180.000000 126.000000 180.000000 162.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1733649538-3488378134)&quot; mask=&quot;url(#d2-1733649538)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KHJvb3QgLSZndDsgcilbMF0=&quot;&gt;&lt;path d=&quot;M 226.657448 65.119315 C 286.600006 105.599998 302.000000 126.000000 302.000000 162.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1733649538-3488378134)&quot; mask=&quot;url(#d2-1733649538)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;mask id=&quot;d2-1733649538&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;383&quot; height=&quot;282&quot;&gt;
&lt;rect x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;383&quot; height=&quot;282&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;

&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;Now insert 55 into right child &lt;code&gt;[60]&lt;/code&gt;:&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 411 282&quot;&gt;&lt;svg class=&quot;d2-967182700 d2-svg&quot; width=&quot;411&quot; height=&quot;282&quot; viewBox=&quot;-25 -25 411 282&quot;&gt;&lt;rect x=&quot;-25.000000&quot; y=&quot;-25.000000&quot; width=&quot;411.000000&quot; height=&quot;282.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-967182700 .text-bold {
	font-family: &quot;d2-967182700-font-bold&quot;;
}
@font-face {
	font-family: d2-967182700-font-bold;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-967182700 .fill-N1{fill:#0A0F25;}
		.d2-967182700 .fill-N2{fill:#676C7E;}
		.d2-967182700 .fill-N3{fill:#9499AB;}
		.d2-967182700 .fill-N4{fill:#CFD2DD;}
		.d2-967182700 .fill-N5{fill:#DEE1EB;}
		.d2-967182700 .fill-N6{fill:#EEF1F8;}
		.d2-967182700 .fill-N7{fill:#FFFFFF;}
		.d2-967182700 .fill-B1{fill:#0D32B2;}
		.d2-967182700 .fill-B2{fill:#0D32B2;}
		.d2-967182700 .fill-B3{fill:#E3E9FD;}
		.d2-967182700 .fill-B4{fill:#E3E9FD;}
		.d2-967182700 .fill-B5{fill:#EDF0FD;}
		.d2-967182700 .fill-B6{fill:#F7F8FE;}
		.d2-967182700 .fill-AA2{fill:#4A6FF3;}
		.d2-967182700 .fill-AA4{fill:#EDF0FD;}
		.d2-967182700 .fill-AA5{fill:#F7F8FE;}
		.d2-967182700 .fill-AB4{fill:#EDF0FD;}
		.d2-967182700 .fill-AB5{fill:#F7F8FE;}
		.d2-967182700 .stroke-N1{stroke:#0A0F25;}
		.d2-967182700 .stroke-N2{stroke:#676C7E;}
		.d2-967182700 .stroke-N3{stroke:#9499AB;}
		.d2-967182700 .stroke-N4{stroke:#CFD2DD;}
		.d2-967182700 .stroke-N5{stroke:#DEE1EB;}
		.d2-967182700 .stroke-N6{stroke:#EEF1F8;}
		.d2-967182700 .stroke-N7{stroke:#FFFFFF;}
		.d2-967182700 .stroke-B1{stroke:#0D32B2;}
		.d2-967182700 .stroke-B2{stroke:#0D32B2;}
		.d2-967182700 .stroke-B3{stroke:#E3E9FD;}
		.d2-967182700 .stroke-B4{stroke:#E3E9FD;}
		.d2-967182700 .stroke-B5{stroke:#EDF0FD;}
		.d2-967182700 .stroke-B6{stroke:#F7F8FE;}
		.d2-967182700 .stroke-AA2{stroke:#4A6FF3;}
		.d2-967182700 .stroke-AA4{stroke:#EDF0FD;}
		.d2-967182700 .stroke-AA5{stroke:#F7F8FE;}
		.d2-967182700 .stroke-AB4{stroke:#EDF0FD;}
		.d2-967182700 .stroke-AB5{stroke:#F7F8FE;}
		.d2-967182700 .background-color-N1{background-color:#0A0F25;}
		.d2-967182700 .background-color-N2{background-color:#676C7E;}
		.d2-967182700 .background-color-N3{background-color:#9499AB;}
		.d2-967182700 .background-color-N4{background-color:#CFD2DD;}
		.d2-967182700 .background-color-N5{background-color:#DEE1EB;}
		.d2-967182700 .background-color-N6{background-color:#EEF1F8;}
		.d2-967182700 .background-color-N7{background-color:#FFFFFF;}
		.d2-967182700 .background-color-B1{background-color:#0D32B2;}
		.d2-967182700 .background-color-B2{background-color:#0D32B2;}
		.d2-967182700 .background-color-B3{background-color:#E3E9FD;}
		.d2-967182700 .background-color-B4{background-color:#E3E9FD;}
		.d2-967182700 .background-color-B5{background-color:#EDF0FD;}
		.d2-967182700 .background-color-B6{background-color:#F7F8FE;}
		.d2-967182700 .background-color-AA2{background-color:#4A6FF3;}
		.d2-967182700 .background-color-AA4{background-color:#EDF0FD;}
		.d2-967182700 .background-color-AA5{background-color:#F7F8FE;}
		.d2-967182700 .background-color-AB4{background-color:#EDF0FD;}
		.d2-967182700 .background-color-AB5{background-color:#F7F8FE;}
		.d2-967182700 .color-N1{color:#0A0F25;}
		.d2-967182700 .color-N2{color:#676C7E;}
		.d2-967182700 .color-N3{color:#9499AB;}
		.d2-967182700 .color-N4{color:#CFD2DD;}
		.d2-967182700 .color-N5{color:#DEE1EB;}
		.d2-967182700 .color-N6{color:#EEF1F8;}
		.d2-967182700 .color-N7{color:#FFFFFF;}
		.d2-967182700 .color-B1{color:#0D32B2;}
		.d2-967182700 .color-B2{color:#0D32B2;}
		.d2-967182700 .color-B3{color:#E3E9FD;}
		.d2-967182700 .color-B4{color:#E3E9FD;}
		.d2-967182700 .color-B5{color:#EDF0FD;}
		.d2-967182700 .color-B6{color:#F7F8FE;}
		.d2-967182700 .color-AA2{color:#4A6FF3;}
		.d2-967182700 .color-AA4{color:#EDF0FD;}
		.d2-967182700 .color-AA5{color:#F7F8FE;}
		.d2-967182700 .color-AB4{color:#EDF0FD;}
		.d2-967182700 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-967182700);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-967182700);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-967182700);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-967182700);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-967182700);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-967182700);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-967182700);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-967182700);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-967182700);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-967182700);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-967182700);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-967182700);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-967182700);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-967182700);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-967182700);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-967182700);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-967182700);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-967182700);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;cm9vdA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;135.000000&quot; y=&quot;0.000000&quot; width=&quot;90.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;180.000000&quot; y=&quot;38.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;30 | 50&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;bA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;0.000000&quot; y=&quot;166.000000&quot; width=&quot;89.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;44.500000&quot; y=&quot;204.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;10 | 20&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;bQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;149.000000&quot; y=&quot;166.000000&quot; width=&quot;62.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;180.000000&quot; y=&quot;204.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;40&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;cg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;271.000000&quot; y=&quot;166.000000&quot; width=&quot;90.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;316.000000&quot; y=&quot;204.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;55 | 60&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KHJvb3QgLSZndDsgbClbMF0=&quot;&gt;&lt;marker id=&quot;mk-d2-967182700-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 133.788342 62.034518 C 62.700001 105.000000 44.500000 126.000000 44.500000 162.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-967182700-3488378134)&quot; mask=&quot;url(#d2-967182700)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KHJvb3QgLSZndDsgbSlbMF0=&quot;&gt;&lt;path d=&quot;M 180.000000 68.000000 C 180.000000 106.000000 180.000000 126.000000 180.000000 162.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-967182700-3488378134)&quot; mask=&quot;url(#d2-967182700)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KHJvb3QgLSZndDsgcilbMF0=&quot;&gt;&lt;path d=&quot;M 226.703317 61.048195 C 297.799988 104.800003 316.000000 126.000000 316.000000 162.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-967182700-3488378134)&quot; mask=&quot;url(#d2-967182700)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;mask id=&quot;d2-967182700&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;411&quot; height=&quot;282&quot;&gt;
&lt;rect x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;411&quot; height=&quot;282&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;

&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;The critical detail: &lt;strong&gt;split on the way down, not on the way up&lt;/strong&gt;. Pre-splitting full children means we never need to walk back up to handle parent overflow — a one-pass algorithm that also simplifies concurrent locking.&lt;/p&gt;
&lt;p&gt;If the root itself fills and splits, a new root is created holding only the promoted middle key. This is the &lt;strong&gt;only way a B-tree grows taller&lt;/strong&gt; — always from the top.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;deletion-three-cases&quot;&gt;Deletion: Three Cases&lt;/h2&gt;
&lt;p&gt;Deletion mirrors insertion. You always want to delete from a leaf, and no node can drop below &lt;code&gt;t-1&lt;/code&gt; keys (the minimum).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Case 1 — Leaf has more than the minimum:&lt;/strong&gt; just remove the key.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Case 2 — Key is in an internal node:&lt;/strong&gt; replace it with its in-order predecessor (the largest key in the left subtree) or in-order successor (the smallest key in the right subtree), then delete that key from the leaf. Same trick as BST deletion.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Case 3 — The leaf is at the minimum (&lt;code&gt;t-1&lt;/code&gt; keys):&lt;/strong&gt; fix the underflow before deleting. Two options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Borrow from a sibling&lt;/strong&gt; that has a spare key. The sibling donates a key up to the parent; the parent sends its separator key down to the underflowing node. This is sometimes called a rotation — distinct from the AVL/red-black rotations used to rebalance binary search trees.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Merge with a sibling&lt;/strong&gt; when no sibling has a spare. Pull the parent’s separator key down and combine two underfull siblings into one valid node. The parent loses a key — which might trigger a cascade upward.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If the root loses its last key during a merge, the root is removed and the merged child becomes the new root. This is the &lt;strong&gt;only way a B-tree shrinks&lt;/strong&gt; — always from the top.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;b-trees-the-database-standard&quot;&gt;B+ Trees: The Database Standard&lt;/h2&gt;
&lt;p&gt;B+ trees make one structural change to the B-tree that turns out to be decisive: &lt;strong&gt;internal nodes store only keys, not values&lt;/strong&gt;. All actual data lives exclusively at the leaf level.&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 686 1809&quot;&gt;&lt;svg class=&quot;d2-282545396 d2-svg&quot; width=&quot;686&quot; height=&quot;1809&quot; viewBox=&quot;-25 -25 686 1809&quot;&gt;&lt;rect x=&quot;-25.000000&quot; y=&quot;-25.000000&quot; width=&quot;686.000000&quot; height=&quot;1809.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-282545396 .text-bold {
	font-family: &quot;d2-282545396-font-bold&quot;;
}
@font-face {
	font-family: d2-282545396-font-bold;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-282545396 .text-italic {
	font-family: &quot;d2-282545396-font-italic&quot;;
}
@font-face {
	font-family: d2-282545396-font-italic;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-282545396 .fill-N1{fill:#0A0F25;}
		.d2-282545396 .fill-N2{fill:#676C7E;}
		.d2-282545396 .fill-N3{fill:#9499AB;}
		.d2-282545396 .fill-N4{fill:#CFD2DD;}
		.d2-282545396 .fill-N5{fill:#DEE1EB;}
		.d2-282545396 .fill-N6{fill:#EEF1F8;}
		.d2-282545396 .fill-N7{fill:#FFFFFF;}
		.d2-282545396 .fill-B1{fill:#0D32B2;}
		.d2-282545396 .fill-B2{fill:#0D32B2;}
		.d2-282545396 .fill-B3{fill:#E3E9FD;}
		.d2-282545396 .fill-B4{fill:#E3E9FD;}
		.d2-282545396 .fill-B5{fill:#EDF0FD;}
		.d2-282545396 .fill-B6{fill:#F7F8FE;}
		.d2-282545396 .fill-AA2{fill:#4A6FF3;}
		.d2-282545396 .fill-AA4{fill:#EDF0FD;}
		.d2-282545396 .fill-AA5{fill:#F7F8FE;}
		.d2-282545396 .fill-AB4{fill:#EDF0FD;}
		.d2-282545396 .fill-AB5{fill:#F7F8FE;}
		.d2-282545396 .stroke-N1{stroke:#0A0F25;}
		.d2-282545396 .stroke-N2{stroke:#676C7E;}
		.d2-282545396 .stroke-N3{stroke:#9499AB;}
		.d2-282545396 .stroke-N4{stroke:#CFD2DD;}
		.d2-282545396 .stroke-N5{stroke:#DEE1EB;}
		.d2-282545396 .stroke-N6{stroke:#EEF1F8;}
		.d2-282545396 .stroke-N7{stroke:#FFFFFF;}
		.d2-282545396 .stroke-B1{stroke:#0D32B2;}
		.d2-282545396 .stroke-B2{stroke:#0D32B2;}
		.d2-282545396 .stroke-B3{stroke:#E3E9FD;}
		.d2-282545396 .stroke-B4{stroke:#E3E9FD;}
		.d2-282545396 .stroke-B5{stroke:#EDF0FD;}
		.d2-282545396 .stroke-B6{stroke:#F7F8FE;}
		.d2-282545396 .stroke-AA2{stroke:#4A6FF3;}
		.d2-282545396 .stroke-AA4{stroke:#EDF0FD;}
		.d2-282545396 .stroke-AA5{stroke:#F7F8FE;}
		.d2-282545396 .stroke-AB4{stroke:#EDF0FD;}
		.d2-282545396 .stroke-AB5{stroke:#F7F8FE;}
		.d2-282545396 .background-color-N1{background-color:#0A0F25;}
		.d2-282545396 .background-color-N2{background-color:#676C7E;}
		.d2-282545396 .background-color-N3{background-color:#9499AB;}
		.d2-282545396 .background-color-N4{background-color:#CFD2DD;}
		.d2-282545396 .background-color-N5{background-color:#DEE1EB;}
		.d2-282545396 .background-color-N6{background-color:#EEF1F8;}
		.d2-282545396 .background-color-N7{background-color:#FFFFFF;}
		.d2-282545396 .background-color-B1{background-color:#0D32B2;}
		.d2-282545396 .background-color-B2{background-color:#0D32B2;}
		.d2-282545396 .background-color-B3{background-color:#E3E9FD;}
		.d2-282545396 .background-color-B4{background-color:#E3E9FD;}
		.d2-282545396 .background-color-B5{background-color:#EDF0FD;}
		.d2-282545396 .background-color-B6{background-color:#F7F8FE;}
		.d2-282545396 .background-color-AA2{background-color:#4A6FF3;}
		.d2-282545396 .background-color-AA4{background-color:#EDF0FD;}
		.d2-282545396 .background-color-AA5{background-color:#F7F8FE;}
		.d2-282545396 .background-color-AB4{background-color:#EDF0FD;}
		.d2-282545396 .background-color-AB5{background-color:#F7F8FE;}
		.d2-282545396 .color-N1{color:#0A0F25;}
		.d2-282545396 .color-N2{color:#676C7E;}
		.d2-282545396 .color-N3{color:#9499AB;}
		.d2-282545396 .color-N4{color:#CFD2DD;}
		.d2-282545396 .color-N5{color:#DEE1EB;}
		.d2-282545396 .color-N6{color:#EEF1F8;}
		.d2-282545396 .color-N7{color:#FFFFFF;}
		.d2-282545396 .color-B1{color:#0D32B2;}
		.d2-282545396 .color-B2{color:#0D32B2;}
		.d2-282545396 .color-B3{color:#E3E9FD;}
		.d2-282545396 .color-B4{color:#E3E9FD;}
		.d2-282545396 .color-B5{color:#EDF0FD;}
		.d2-282545396 .color-B6{color:#F7F8FE;}
		.d2-282545396 .color-AA2{color:#4A6FF3;}
		.d2-282545396 .color-AA4{color:#EDF0FD;}
		.d2-282545396 .color-AA5{color:#F7F8FE;}
		.d2-282545396 .color-AB4{color:#EDF0FD;}
		.d2-282545396 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-282545396);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-282545396);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-282545396);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-282545396);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-282545396);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-282545396);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-282545396);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-282545396);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-282545396);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-282545396);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-282545396);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-282545396);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-282545396);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-282545396);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-282545396);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-282545396);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-282545396);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-282545396);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;cm9vdA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;ellipse rx=&quot;112.000000&quot; ry=&quot;39.500000&quot; cx=&quot;339.000000&quot; cy=&quot;39.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;shape stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/ellipse&gt;&lt;/g&gt;&lt;text x=&quot;339.000000&quot; y=&quot;37.000000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;339.000000&quot; dy=&quot;0.000000&quot;&gt;30 | 70&lt;/tspan&gt;&lt;tspan x=&quot;339.000000&quot; dy=&quot;18.500000&quot;&gt;— routing only —&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;aWw=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;ellipse rx=&quot;111.000000&quot; ry=&quot;39.500000&quot; cx=&quot;519.000000&quot; cy=&quot;218.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;shape stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/ellipse&gt;&lt;/g&gt;&lt;text x=&quot;519.000000&quot; y=&quot;216.000000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;519.000000&quot; dy=&quot;0.000000&quot;&gt;10 | 20&lt;/tspan&gt;&lt;tspan x=&quot;519.000000&quot; dy=&quot;18.500000&quot;&gt;— routing only —&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;aW0=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;ellipse rx=&quot;112.000000&quot; ry=&quot;39.500000&quot; cx=&quot;302.000000&quot; cy=&quot;771.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;shape stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/ellipse&gt;&lt;/g&gt;&lt;text x=&quot;302.000000&quot; y=&quot;769.000000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;302.000000&quot; dy=&quot;0.000000&quot;&gt;40 | 60&lt;/tspan&gt;&lt;tspan x=&quot;302.000000&quot; dy=&quot;18.500000&quot;&gt;— routing only —&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;aXI=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;ellipse rx=&quot;112.000000&quot; ry=&quot;39.500000&quot; cx=&quot;112.000000&quot; cy=&quot;1345.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;shape stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/ellipse&gt;&lt;/g&gt;&lt;text x=&quot;112.000000&quot; y=&quot;1343.000000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;112.000000&quot; dy=&quot;0.000000&quot;&gt;80&lt;/tspan&gt;&lt;tspan x=&quot;112.000000&quot; dy=&quot;18.500000&quot;&gt;— routing only —&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;bDE=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;563.000000&quot; y=&quot;358.000000&quot; width=&quot;73.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;599.500000&quot; y=&quot;396.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;5 | 7&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;bDI=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;517.000000&quot; y=&quot;545.000000&quot; width=&quot;89.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;561.500000&quot; y=&quot;583.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;10 | 20&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;bDM=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;474.000000&quot; y=&quot;739.000000&quot; width=&quot;90.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;519.000000&quot; y=&quot;777.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;25 | 28&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;bDQ=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;457.000000&quot; y=&quot;932.000000&quot; width=&quot;90.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;502.000000&quot; y=&quot;970.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;30 | 35&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;bDU=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;414.000000&quot; y=&quot;1119.000000&quot; width=&quot;90.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;459.000000&quot; y=&quot;1157.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;40 | 55&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;bDY=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;365.000000&quot; y=&quot;1313.000000&quot; width=&quot;90.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;410.000000&quot; y=&quot;1351.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;60 | 65&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;bDc=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;348.000000&quot; y=&quot;1506.000000&quot; width=&quot;90.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;393.000000&quot; y=&quot;1544.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;70 | 75&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;bDg=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;257.000000&quot; y=&quot;1693.000000&quot; width=&quot;90.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;302.000000&quot; y=&quot;1731.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;80 | 90&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KHJvb3QgLSZndDsgaWwpWzBd&quot;&gt;&lt;marker id=&quot;mk-d2-282545396-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 405.791190 72.889741 C 495.799988 117.599998 518.799011 139.000000 518.979901 175.000050&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-282545396-3488378134)&quot; mask=&quot;url(#d2-282545396)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KHJvb3QgLSZndDsgaW0pWzBd&quot;&gt;&lt;path d=&quot;M 322.217719 80.840662 C 306.000000 119.000000 301.750000 146.899994 301.750000 173.750000 C 301.750000 200.600006 301.750000 236.399994 301.750000 263.250000 C 301.750000 290.100006 301.750000 324.600006 301.750000 349.500000 C 301.750000 374.399994 301.750000 409.700012 301.750000 437.750000 C 301.750000 465.799988 301.750000 503.200012 301.750000 531.250000 C 301.750000 559.299988 301.799988 683.599976 301.983470 728.000034&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-282545396-3488378134)&quot; mask=&quot;url(#d2-282545396)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KHJvb3QgLSZndDsgaXIpWzBd&quot;&gt;&lt;path d=&quot;M 262.139687 69.734328 C 142.399002 117.000000 112.000000 146.899994 112.000000 173.750000 C 112.000000 200.600006 112.000000 236.399994 112.000000 263.250000 C 112.000000 290.100006 112.000000 324.600006 112.000000 349.500000 C 112.000000 374.399994 112.000000 409.700012 112.000000 437.750000 C 112.000000 465.799988 112.000000 503.200012 112.000000 531.250000 C 112.000000 559.299988 112.000000 596.700012 112.000000 624.750000 C 112.000000 652.799988 112.000000 691.500000 112.000000 721.500000 C 112.000000 751.500000 112.000000 791.500000 112.000000 821.500000 C 112.000000 851.500000 112.000000 890.200012 112.000000 918.250000 C 112.000000 946.299988 112.000000 983.700012 112.000000 1011.750000 C 112.000000 1039.800049 112.000000 1077.199951 112.000000 1105.250000 C 112.000000 1133.300049 112.000000 1257.599976 112.000000 1302.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-282545396-3488378134)&quot; mask=&quot;url(#d2-282545396)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KGlsIC0mZ3Q7IGwxKVswXQ==&quot;&gt;&lt;path d=&quot;M 554.329173 257.494422 C 590.000000 297.600006 599.250000 318.000000 599.250000 354.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-282545396-3488378134)&quot; mask=&quot;url(#d2-282545396)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KGlsIC0mZ3Q7IGwyKVswXQ==&quot;&gt;&lt;path d=&quot;M 521.069958 259.998776 C 522.400024 298.000000 522.750000 324.600006 522.750000 349.500000 C 522.750000 374.399994 527.750000 496.700012 546.233106 541.798780&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-282545396-3488378134)&quot; mask=&quot;url(#d2-282545396)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KGlsIC0mZ3Q7IGwzKVswXQ==&quot;&gt;&lt;path d=&quot;M 476.526486 256.352315 C 431.799988 297.399994 420.250000 324.600006 420.250000 349.500000 C 420.250000 374.399994 420.250000 409.700012 420.250000 437.750000 C 420.250000 465.799988 420.250000 503.200012 420.250000 531.250000 C 420.250000 559.299988 433.449005 684.900024 483.438021 735.650281&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-282545396-3488378134)&quot; mask=&quot;url(#d2-282545396)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KGltIC0mZ3Q7IGw0KVswXQ==&quot;&gt;&lt;path d=&quot;M 339.382051 810.445661 C 385.799988 859.000000 410.950012 883.700012 460.812493 929.785032&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-282545396-3488378134)&quot; mask=&quot;url(#d2-282545396)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KGltIC0mZ3Q7IGw1KVswXQ==&quot;&gt;&lt;path d=&quot;M 316.710705 812.869465 C 334.399994 859.400024 339.000000 890.200012 339.000000 918.250000 C 339.000000 946.299988 354.399994 1070.699951 412.864644 1117.016144&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-282545396-3488378134)&quot; mask=&quot;url(#d2-282545396)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KGltIC0mZ3Q7IGw2KVswXQ==&quot;&gt;&lt;path d=&quot;M 274.904769 811.673460 C 243.800003 859.200012 235.750000 890.200012 235.750000 918.250000 C 235.750000 946.299988 235.750000 983.700012 235.750000 1011.750000 C 235.750000 1039.800049 235.750000 1077.199951 235.750000 1105.250000 C 235.750000 1133.300049 261.549988 1260.300049 361.280342 1317.509655&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-282545396-3488378134)&quot; mask=&quot;url(#d2-282545396)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KGlyIC0mZ3Q7IGw3KVswXQ==&quot;&gt;&lt;path d=&quot;M 150.379021 1384.448551 C 196.600006 1433.000000 236.500000 1459.699951 344.932543 1514.690788&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-282545396-3488378134)&quot; mask=&quot;url(#d2-282545396)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KGlyIC0mZ3Q7IGw4KVswXQ==&quot;&gt;&lt;path d=&quot;M 107.802621 1386.990237 C 103.199997 1433.400024 102.000000 1464.199951 102.000000 1492.250000 C 102.000000 1520.300049 132.949997 1646.987061 253.127240 1703.240274&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-282545396-3488378134)&quot; mask=&quot;url(#d2-282545396)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KGwxIC0mZ3Q7IGwyKVswXQ==&quot;&gt;&lt;marker id=&quot;mk-d2-282545396-2177206569&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B2&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 599.250000 425.500000 C 599.250000 472.299988 594.250000 496.700012 575.766894 541.798780&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:6.000000,5.919384;&quot; marker-end=&quot;url(#mk-d2-282545396-2177206569)&quot; mask=&quot;url(#d2-282545396)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;596.500000&quot; y=&quot;492.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;next&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KGwyIC0mZ3Q7IGwzKVswXQ==&quot;&gt;&lt;path d=&quot;M 561.000000 612.500000 C 561.000000 659.299988 555.338013 684.900024 534.248774 734.815369&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:6.000000,5.919384;&quot; marker-end=&quot;url(#mk-d2-282545396-2177206569)&quot; mask=&quot;url(#d2-282545396)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;557.500000&quot; y=&quot;682.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;next&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KGwzIC0mZ3Q7IGw0KVswXQ==&quot;&gt;&lt;path d=&quot;M 518.750000 807.500000 C 518.750000 858.299988 516.549011 883.700012 508.459785 928.563478&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:6.000000,5.919384;&quot; marker-end=&quot;url(#mk-d2-282545396-2177206569)&quot; mask=&quot;url(#d2-282545396)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;517.500000&quot; y=&quot;875.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;next&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KGw0IC0mZ3Q7IGw1KVswXQ==&quot;&gt;&lt;path d=&quot;M 501.500000 999.500000 C 501.500000 1046.300049 495.899994 1070.699951 475.168669 1115.864681&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:6.000000,5.919384;&quot; marker-end=&quot;url(#mk-d2-282545396-2177206569)&quot; mask=&quot;url(#d2-282545396)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;498.500000&quot; y=&quot;1066.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;next&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KGw1IC0mZ3Q7IGw2KVswXQ==&quot;&gt;&lt;path d=&quot;M 459.000000 1186.500000 C 459.000000 1233.300049 452.467010 1258.900024 428.089816 1308.904495&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:6.000000,5.919384;&quot; marker-end=&quot;url(#mk-d2-282545396-2177206569)&quot; mask=&quot;url(#d2-282545396)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;454.500000&quot; y=&quot;1257.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;next&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KGw2IC0mZ3Q7IGw3KVswXQ==&quot;&gt;&lt;path d=&quot;M 410.250000 1381.500000 C 410.250000 1432.300049 408.049988 1457.699951 399.959860 1502.563492&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:6.000000,5.919384;&quot; marker-end=&quot;url(#mk-d2-282545396-2177206569)&quot; mask=&quot;url(#d2-282545396)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;409.500000&quot; y=&quot;1449.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;next&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KGw3IC0mZ3Q7IGw4KVswXQ==&quot;&gt;&lt;path d=&quot;M 393.000000 1573.500000 C 393.000000 1620.300049 381.200012 1644.699951 336.780899 1690.624831&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:6.000000,5.919384;&quot; marker-end=&quot;url(#mk-d2-282545396-2177206569)&quot; mask=&quot;url(#d2-282545396)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;382.500000&quot; y=&quot;1647.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;next&lt;/text&gt;&lt;/g&gt;&lt;mask id=&quot;d2-282545396&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;686&quot; height=&quot;1809&quot;&gt;
&lt;rect x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;686&quot; height=&quot;1809&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;580.000000&quot; y=&quot;476.000000&quot; width=&quot;33&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;541.000000&quot; y=&quot;666.000000&quot; width=&quot;33&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;501.000000&quot; y=&quot;859.000000&quot; width=&quot;33&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;482.000000&quot; y=&quot;1050.000000&quot; width=&quot;33&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;438.000000&quot; y=&quot;1241.000000&quot; width=&quot;33&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;393.000000&quot; y=&quot;1433.000000&quot; width=&quot;33&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;366.000000&quot; y=&quot;1631.000000&quot; width=&quot;33&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;Two things stand out immediately.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Internal nodes are denser.&lt;/strong&gt; Without values, they hold far more keys per disk page. A 16KB page with 8-byte keys and 8-byte child pointers fits roughly several hundred to ~1,000 keys after accounting for page header and metadata. That is the branching factor. A 3-level tree now covers 1,000³ = &lt;strong&gt;one billion rows&lt;/strong&gt;. The same tree in a standard B-tree, carrying 100-byte records in every node, might only branch by 100 — covering one million rows.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Leaf nodes form a sorted linked list.&lt;/strong&gt; Every leaf has a pointer to the next leaf in key order. This is the feature that makes databases fast for the queries they actually run.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;range-queries-the-decisive-advantage&quot;&gt;Range Queries: The Decisive Advantage&lt;/h2&gt;
&lt;p&gt;A point lookup (&lt;code&gt;WHERE id = 42&lt;/code&gt;) is equally fast on a B-tree and a B+ tree — navigate to the leaf, return the value.&lt;/p&gt;
&lt;p&gt;A range query (&lt;code&gt;WHERE age BETWEEN 25 AND 55&lt;/code&gt;) is where B+ trees dominate.&lt;/p&gt;
&lt;p&gt;In a B-tree, matching keys can be scattered across internal and leaf nodes. You must traverse the tree for each one.&lt;/p&gt;
&lt;p&gt;In a B+ tree:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to the first leaf containing 25 — O(log n), one tree traversal&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Follow the linked list rightward&lt;/strong&gt;, collecting every key until you pass 55&lt;/li&gt;
&lt;/ol&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 797 116&quot;&gt;&lt;svg class=&quot;d2-1285219160 d2-svg&quot; width=&quot;797&quot; height=&quot;116&quot; viewBox=&quot;-25 -25 797 116&quot;&gt;&lt;rect x=&quot;-25.000000&quot; y=&quot;-25.000000&quot; width=&quot;797.000000&quot; height=&quot;116.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-1285219160 .text-bold {
	font-family: &quot;d2-1285219160-font-bold&quot;;
}
@font-face {
	font-family: d2-1285219160-font-bold;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-1285219160 .text-italic {
	font-family: &quot;d2-1285219160-font-italic&quot;;
}
@font-face {
	font-family: d2-1285219160-font-italic;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-1285219160 .fill-N1{fill:#0A0F25;}
		.d2-1285219160 .fill-N2{fill:#676C7E;}
		.d2-1285219160 .fill-N3{fill:#9499AB;}
		.d2-1285219160 .fill-N4{fill:#CFD2DD;}
		.d2-1285219160 .fill-N5{fill:#DEE1EB;}
		.d2-1285219160 .fill-N6{fill:#EEF1F8;}
		.d2-1285219160 .fill-N7{fill:#FFFFFF;}
		.d2-1285219160 .fill-B1{fill:#0D32B2;}
		.d2-1285219160 .fill-B2{fill:#0D32B2;}
		.d2-1285219160 .fill-B3{fill:#E3E9FD;}
		.d2-1285219160 .fill-B4{fill:#E3E9FD;}
		.d2-1285219160 .fill-B5{fill:#EDF0FD;}
		.d2-1285219160 .fill-B6{fill:#F7F8FE;}
		.d2-1285219160 .fill-AA2{fill:#4A6FF3;}
		.d2-1285219160 .fill-AA4{fill:#EDF0FD;}
		.d2-1285219160 .fill-AA5{fill:#F7F8FE;}
		.d2-1285219160 .fill-AB4{fill:#EDF0FD;}
		.d2-1285219160 .fill-AB5{fill:#F7F8FE;}
		.d2-1285219160 .stroke-N1{stroke:#0A0F25;}
		.d2-1285219160 .stroke-N2{stroke:#676C7E;}
		.d2-1285219160 .stroke-N3{stroke:#9499AB;}
		.d2-1285219160 .stroke-N4{stroke:#CFD2DD;}
		.d2-1285219160 .stroke-N5{stroke:#DEE1EB;}
		.d2-1285219160 .stroke-N6{stroke:#EEF1F8;}
		.d2-1285219160 .stroke-N7{stroke:#FFFFFF;}
		.d2-1285219160 .stroke-B1{stroke:#0D32B2;}
		.d2-1285219160 .stroke-B2{stroke:#0D32B2;}
		.d2-1285219160 .stroke-B3{stroke:#E3E9FD;}
		.d2-1285219160 .stroke-B4{stroke:#E3E9FD;}
		.d2-1285219160 .stroke-B5{stroke:#EDF0FD;}
		.d2-1285219160 .stroke-B6{stroke:#F7F8FE;}
		.d2-1285219160 .stroke-AA2{stroke:#4A6FF3;}
		.d2-1285219160 .stroke-AA4{stroke:#EDF0FD;}
		.d2-1285219160 .stroke-AA5{stroke:#F7F8FE;}
		.d2-1285219160 .stroke-AB4{stroke:#EDF0FD;}
		.d2-1285219160 .stroke-AB5{stroke:#F7F8FE;}
		.d2-1285219160 .background-color-N1{background-color:#0A0F25;}
		.d2-1285219160 .background-color-N2{background-color:#676C7E;}
		.d2-1285219160 .background-color-N3{background-color:#9499AB;}
		.d2-1285219160 .background-color-N4{background-color:#CFD2DD;}
		.d2-1285219160 .background-color-N5{background-color:#DEE1EB;}
		.d2-1285219160 .background-color-N6{background-color:#EEF1F8;}
		.d2-1285219160 .background-color-N7{background-color:#FFFFFF;}
		.d2-1285219160 .background-color-B1{background-color:#0D32B2;}
		.d2-1285219160 .background-color-B2{background-color:#0D32B2;}
		.d2-1285219160 .background-color-B3{background-color:#E3E9FD;}
		.d2-1285219160 .background-color-B4{background-color:#E3E9FD;}
		.d2-1285219160 .background-color-B5{background-color:#EDF0FD;}
		.d2-1285219160 .background-color-B6{background-color:#F7F8FE;}
		.d2-1285219160 .background-color-AA2{background-color:#4A6FF3;}
		.d2-1285219160 .background-color-AA4{background-color:#EDF0FD;}
		.d2-1285219160 .background-color-AA5{background-color:#F7F8FE;}
		.d2-1285219160 .background-color-AB4{background-color:#EDF0FD;}
		.d2-1285219160 .background-color-AB5{background-color:#F7F8FE;}
		.d2-1285219160 .color-N1{color:#0A0F25;}
		.d2-1285219160 .color-N2{color:#676C7E;}
		.d2-1285219160 .color-N3{color:#9499AB;}
		.d2-1285219160 .color-N4{color:#CFD2DD;}
		.d2-1285219160 .color-N5{color:#DEE1EB;}
		.d2-1285219160 .color-N6{color:#EEF1F8;}
		.d2-1285219160 .color-N7{color:#FFFFFF;}
		.d2-1285219160 .color-B1{color:#0D32B2;}
		.d2-1285219160 .color-B2{color:#0D32B2;}
		.d2-1285219160 .color-B3{color:#E3E9FD;}
		.d2-1285219160 .color-B4{color:#E3E9FD;}
		.d2-1285219160 .color-B5{color:#EDF0FD;}
		.d2-1285219160 .color-B6{color:#F7F8FE;}
		.d2-1285219160 .color-AA2{color:#4A6FF3;}
		.d2-1285219160 .color-AA4{color:#EDF0FD;}
		.d2-1285219160 .color-AA5{color:#F7F8FE;}
		.d2-1285219160 .color-AB4{color:#EDF0FD;}
		.d2-1285219160 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-1285219160);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-1285219160);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-1285219160);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-1285219160);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-1285219160);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-1285219160);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-1285219160);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-1285219160);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-1285219160);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-1285219160);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-1285219160);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-1285219160);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-1285219160);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-1285219160);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-1285219160);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-1285219160);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-1285219160);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-1285219160);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;bDM=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;0.000000&quot; y=&quot;0.000000&quot; width=&quot;90.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;45.000000&quot; y=&quot;38.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;25 | 28&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;bDQ=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;219.000000&quot; y=&quot;0.000000&quot; width=&quot;90.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;264.000000&quot; y=&quot;38.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;30 | 35&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;bDU=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;438.000000&quot; y=&quot;0.000000&quot; width=&quot;90.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;483.000000&quot; y=&quot;38.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;40 | 55&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;bDY=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;657.000000&quot; y=&quot;0.000000&quot; width=&quot;90.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;702.000000&quot; y=&quot;38.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;60 | 65&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KGwzIC0mZ3Q7IGw0KVswXQ==&quot;&gt;&lt;marker id=&quot;mk-d2-1285219160-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 91.500000 33.000000 C 141.500000 33.000000 167.500000 33.000000 215.500000 33.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1285219160-3488378134)&quot; mask=&quot;url(#d2-1285219160)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;154.500000&quot; y=&quot;39.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;next&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KGw0IC0mZ3Q7IGw1KVswXQ==&quot;&gt;&lt;path d=&quot;M 310.500000 33.000000 C 360.500000 33.000000 386.500000 33.000000 434.500000 33.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1285219160-3488378134)&quot; mask=&quot;url(#d2-1285219160)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;373.500000&quot; y=&quot;39.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;next&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KGw1IC0mZ3Q7IGw2KVswXQ==&quot;&gt;&lt;path d=&quot;M 529.500000 33.000000 C 579.500000 33.000000 605.500000 33.000000 653.500000 33.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1285219160-3488378134)&quot; mask=&quot;url(#d2-1285219160)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;592.500000&quot; y=&quot;39.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;next&lt;/text&gt;&lt;/g&gt;&lt;mask id=&quot;d2-1285219160&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;797&quot; height=&quot;116&quot;&gt;
&lt;rect x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;797&quot; height=&quot;116&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;138.000000&quot; y=&quot;23.000000&quot; width=&quot;33&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;357.000000&quot; y=&quot;23.000000&quot; width=&quot;33&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;576.000000&quot; y=&quot;23.000000&quot; width=&quot;33&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;No backtracking. No re-traversing the tree. The linked list turns a range query into a sequential scan of exactly the relevant pages. Sequential reads are 10–100x faster than random reads on spinning disks; even on SSDs the gap is 2–10x and prefetching makes sequential scans dramatically cheaper.&lt;/p&gt;
&lt;p&gt;This is why every major relational database — PostgreSQL, MySQL InnoDB, SQLite, SQL Server — uses B+ trees as the primary index structure.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;one-structural-difference-promoted-vs-copied-keys&quot;&gt;One Structural Difference: Promoted vs. Copied Keys&lt;/h2&gt;
&lt;p&gt;When a node splits in a B-tree, the middle key &lt;strong&gt;moves up&lt;/strong&gt; — it leaves the child and lives only in the parent.&lt;/p&gt;
&lt;p&gt;When a node splits in a B+ tree, the middle key &lt;strong&gt;copies up&lt;/strong&gt; — it stays in the right leaf and also appears in the parent as a routing guide.&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 362 680&quot;&gt;&lt;svg class=&quot;d2-182811712 d2-svg&quot; width=&quot;362&quot; height=&quot;680&quot; viewBox=&quot;-5 -9 362 680&quot;&gt;&lt;rect x=&quot;-5.000000&quot; y=&quot;-9.000000&quot; width=&quot;362.000000&quot; height=&quot;680.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-182811712 .text {
	font-family: &quot;d2-182811712-font-regular&quot;;
}
@font-face {
	font-family: d2-182811712-font-regular;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-182811712 .text-bold {
	font-family: &quot;d2-182811712-font-bold&quot;;
}
@font-face {
	font-family: d2-182811712-font-bold;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-182811712 .fill-N1{fill:#0A0F25;}
		.d2-182811712 .fill-N2{fill:#676C7E;}
		.d2-182811712 .fill-N3{fill:#9499AB;}
		.d2-182811712 .fill-N4{fill:#CFD2DD;}
		.d2-182811712 .fill-N5{fill:#DEE1EB;}
		.d2-182811712 .fill-N6{fill:#EEF1F8;}
		.d2-182811712 .fill-N7{fill:#FFFFFF;}
		.d2-182811712 .fill-B1{fill:#0D32B2;}
		.d2-182811712 .fill-B2{fill:#0D32B2;}
		.d2-182811712 .fill-B3{fill:#E3E9FD;}
		.d2-182811712 .fill-B4{fill:#E3E9FD;}
		.d2-182811712 .fill-B5{fill:#EDF0FD;}
		.d2-182811712 .fill-B6{fill:#F7F8FE;}
		.d2-182811712 .fill-AA2{fill:#4A6FF3;}
		.d2-182811712 .fill-AA4{fill:#EDF0FD;}
		.d2-182811712 .fill-AA5{fill:#F7F8FE;}
		.d2-182811712 .fill-AB4{fill:#EDF0FD;}
		.d2-182811712 .fill-AB5{fill:#F7F8FE;}
		.d2-182811712 .stroke-N1{stroke:#0A0F25;}
		.d2-182811712 .stroke-N2{stroke:#676C7E;}
		.d2-182811712 .stroke-N3{stroke:#9499AB;}
		.d2-182811712 .stroke-N4{stroke:#CFD2DD;}
		.d2-182811712 .stroke-N5{stroke:#DEE1EB;}
		.d2-182811712 .stroke-N6{stroke:#EEF1F8;}
		.d2-182811712 .stroke-N7{stroke:#FFFFFF;}
		.d2-182811712 .stroke-B1{stroke:#0D32B2;}
		.d2-182811712 .stroke-B2{stroke:#0D32B2;}
		.d2-182811712 .stroke-B3{stroke:#E3E9FD;}
		.d2-182811712 .stroke-B4{stroke:#E3E9FD;}
		.d2-182811712 .stroke-B5{stroke:#EDF0FD;}
		.d2-182811712 .stroke-B6{stroke:#F7F8FE;}
		.d2-182811712 .stroke-AA2{stroke:#4A6FF3;}
		.d2-182811712 .stroke-AA4{stroke:#EDF0FD;}
		.d2-182811712 .stroke-AA5{stroke:#F7F8FE;}
		.d2-182811712 .stroke-AB4{stroke:#EDF0FD;}
		.d2-182811712 .stroke-AB5{stroke:#F7F8FE;}
		.d2-182811712 .background-color-N1{background-color:#0A0F25;}
		.d2-182811712 .background-color-N2{background-color:#676C7E;}
		.d2-182811712 .background-color-N3{background-color:#9499AB;}
		.d2-182811712 .background-color-N4{background-color:#CFD2DD;}
		.d2-182811712 .background-color-N5{background-color:#DEE1EB;}
		.d2-182811712 .background-color-N6{background-color:#EEF1F8;}
		.d2-182811712 .background-color-N7{background-color:#FFFFFF;}
		.d2-182811712 .background-color-B1{background-color:#0D32B2;}
		.d2-182811712 .background-color-B2{background-color:#0D32B2;}
		.d2-182811712 .background-color-B3{background-color:#E3E9FD;}
		.d2-182811712 .background-color-B4{background-color:#E3E9FD;}
		.d2-182811712 .background-color-B5{background-color:#EDF0FD;}
		.d2-182811712 .background-color-B6{background-color:#F7F8FE;}
		.d2-182811712 .background-color-AA2{background-color:#4A6FF3;}
		.d2-182811712 .background-color-AA4{background-color:#EDF0FD;}
		.d2-182811712 .background-color-AA5{background-color:#F7F8FE;}
		.d2-182811712 .background-color-AB4{background-color:#EDF0FD;}
		.d2-182811712 .background-color-AB5{background-color:#F7F8FE;}
		.d2-182811712 .color-N1{color:#0A0F25;}
		.d2-182811712 .color-N2{color:#676C7E;}
		.d2-182811712 .color-N3{color:#9499AB;}
		.d2-182811712 .color-N4{color:#CFD2DD;}
		.d2-182811712 .color-N5{color:#DEE1EB;}
		.d2-182811712 .color-N6{color:#EEF1F8;}
		.d2-182811712 .color-N7{color:#FFFFFF;}
		.d2-182811712 .color-B1{color:#0D32B2;}
		.d2-182811712 .color-B2{color:#0D32B2;}
		.d2-182811712 .color-B3{color:#E3E9FD;}
		.d2-182811712 .color-B4{color:#E3E9FD;}
		.d2-182811712 .color-B5{color:#EDF0FD;}
		.d2-182811712 .color-B6{color:#F7F8FE;}
		.d2-182811712 .color-AA2{color:#4A6FF3;}
		.d2-182811712 .color-AA4{color:#EDF0FD;}
		.d2-182811712 .color-AA5{color:#F7F8FE;}
		.d2-182811712 .color-AB4{color:#EDF0FD;}
		.d2-182811712 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-182811712);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-182811712);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-182811712);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-182811712);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-182811712);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-182811712);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-182811712);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-182811712);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-182811712);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-182811712);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-182811712);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-182811712);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-182811712);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-182811712);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-182811712);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-182811712);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-182811712);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-182811712);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;YnRyZWU=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;20.000000&quot; y=&quot;56.000000&quot; width=&quot;298.000000&quot; height=&quot;252.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#E3E9FD&quot; class=&quot;stroke-B1 fill-B4&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;169.000000&quot; y=&quot;43.000000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:28px&quot;&gt;B-Tree&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;YnB0cmVl&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;20.000000&quot; y=&quot;394.000000&quot; width=&quot;312.000000&quot; height=&quot;252.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#E3E9FD&quot; class=&quot;stroke-B1 fill-B4&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;176.000000&quot; y=&quot;381.000000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:28px&quot;&gt;B+Tree&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;YnRyZWUuYnJvb3Q=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;50.000000&quot; y=&quot;149.000000&quot; width=&quot;62.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;81.000000&quot; y=&quot;187.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;20&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;YnRyZWUuYmw=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;227.000000&quot; y=&quot;86.000000&quot; width=&quot;61.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;257.500000&quot; y=&quot;124.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;10&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;YnRyZWUuYnI=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;226.000000&quot; y=&quot;212.000000&quot; width=&quot;62.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;257.000000&quot; y=&quot;250.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;30&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;YnB0cmVlLmJwcm9vdA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;50.000000&quot; y=&quot;487.000000&quot; width=&quot;62.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;81.000000&quot; y=&quot;525.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;20&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;YnB0cmVlLmJwbA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;227.000000&quot; y=&quot;424.000000&quot; width=&quot;61.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;257.500000&quot; y=&quot;462.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;10&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;YnB0cmVlLmJwcg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;212.000000&quot; y=&quot;550.000000&quot; width=&quot;90.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;257.000000&quot; y=&quot;588.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;20 | 30&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;YnRyZWUuKGJyb290IC0mZ3Q7IGJsKVswXQ==&quot;&gt;&lt;marker id=&quot;mk-d2-182811712-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 113.577005 156.769936 C 152.000000 126.800003 174.899994 119.000000 222.500000 119.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-182811712-3488378134)&quot; mask=&quot;url(#d2-182811712)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;YnRyZWUuKGJyb290IC0mZ3Q7IGJyKVswXQ==&quot;&gt;&lt;path d=&quot;M 113.577005 207.230064 C 152.000000 237.199997 174.800003 245.000000 222.000000 245.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-182811712-3488378134)&quot; mask=&quot;url(#d2-182811712)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;YnB0cmVlLihicHJvb3QgLSZndDsgYnBsKVswXQ==&quot;&gt;&lt;path d=&quot;M 113.577004 494.769936 C 152.000000 464.799988 174.899994 457.000000 222.500000 457.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-182811712-3488378134)&quot; mask=&quot;url(#d2-182811712)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;YnB0cmVlLihicHJvb3QgLSZndDsgYnByKVswXQ==&quot;&gt;&lt;path d=&quot;M 113.577004 545.230064 C 152.000000 575.200012 172.000000 583.000000 208.000000 583.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-182811712-3488378134)&quot; mask=&quot;url(#d2-182811712)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;mask id=&quot;d2-182811712&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-5&quot; y=&quot;-9&quot; width=&quot;362&quot; height=&quot;680&quot;&gt;
&lt;rect x=&quot;-5&quot; y=&quot;-9&quot; width=&quot;362&quot; height=&quot;680&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;

&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;The leaf &lt;code&gt;[20 | 30]&lt;/code&gt; in the B+ tree still contains 20, even though 20 also appears in the parent. Internal nodes are routing indexes, not the authoritative location of data. All data lives in the leaves.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;numbers-that-put-it-in-perspective&quot;&gt;Numbers That Put It in Perspective&lt;/h2&gt;
&lt;p&gt;Assume a 16KB page, 8-byte keys, 8-byte pointers, 100-byte records:&lt;/p&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Structure&lt;/th&gt;&lt;th&gt;Keys per internal node&lt;/th&gt;&lt;th&gt;Rows covered at 3 levels&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;BST&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;7&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;B-tree (t=50)&lt;/td&gt;&lt;td&gt;~99&lt;/td&gt;&lt;td&gt;~970,000&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;B+ tree&lt;/td&gt;&lt;td&gt;~1,000&lt;/td&gt;&lt;td&gt;~1,000,000,000&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;B+ trees get that extra order of magnitude because internal nodes never carry record data — every byte goes toward branching. At a billion rows and 3 levels, you need exactly &lt;strong&gt;3 disk reads&lt;/strong&gt; per point lookup. In practice the upper levels of the tree are kept hot in the buffer cache, so the amortized cost is closer to one read per query.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;













































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;B-Tree&lt;/th&gt;&lt;th&gt;B+ Tree&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Data stored at&lt;/td&gt;&lt;td&gt;Any node&lt;/td&gt;&lt;td&gt;Leaves only&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Internal nodes contain&lt;/td&gt;&lt;td&gt;Keys + values&lt;/td&gt;&lt;td&gt;Keys only (denser)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Leaf linked list&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Point query&lt;/td&gt;&lt;td&gt;O(log n)&lt;/td&gt;&lt;td&gt;O(log n)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Range query&lt;/td&gt;&lt;td&gt;Tree traversal per key&lt;/td&gt;&lt;td&gt;Follow linked list — O(log n + k)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Typical height (1B rows)&lt;/td&gt;&lt;td&gt;~5 levels&lt;/td&gt;&lt;td&gt;~3 levels&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Used by&lt;/td&gt;&lt;td&gt;Many filesystems (HFS+, ext4, NTFS, APFS, Btrfs use B-trees or B+ trees)&lt;/td&gt;&lt;td&gt;Databases (PostgreSQL, MySQL, SQLite, SQL Server)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The mental model builds directly from what you already know:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;BST&lt;/strong&gt; — one key, two children, branch by 2&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B-tree&lt;/strong&gt; — many keys, many children, branch by many, data anywhere&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B+ tree&lt;/strong&gt; — many keys, many children, data only at leaves, leaves linked in sorted order&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The B+ tree is not a micro-optimization of the B-tree. It is a deliberate trade: give up the ability to find data in internal nodes, gain the ability to do range scans in O(k) time after a single O(log n) lookup.&lt;/p&gt;
&lt;p&gt;That trade is the reason &lt;code&gt;WHERE created_at BETWEEN &apos;2026-01-01&apos; AND &apos;2026-03-31&apos;&lt;/code&gt; returns in milliseconds instead of minutes.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;related-reading&quot;&gt;Related reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/db-storage-and-indexing/&quot;&gt;How Databases Actually Store and Find Your Data&lt;/a&gt; — pages, heaps, and how indexes physically connect to rows.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/postgres-indexing/&quot;&gt;PostgreSQL Indexing Deep Dive&lt;/a&gt; — applies B+ tree theory to a real database, plus GIN, GiST, BRIN, and hash indexes.&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>PostgreSQL Indexing: Internals, Types, and Trade-offs</title><link>https://abhimanyunagurkar.com/blog/postgres-indexing/</link><guid isPermaLink="true">https://abhimanyunagurkar.com/blog/postgres-indexing/</guid><description>A practical guide to PostgreSQL indexes: B-tree, GIN, GiST, BRIN, hash — when to use each, composite key ordering, and CONCURRENTLY pitfalls.</description><pubDate>Sun, 26 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;An index is the single most impactful performance tool in a relational database. It can turn a 30-second query into a 2ms one. It can also double your write latency, bloat your storage, and confuse the query planner — all silently. This post goes deep on how indexes actually work inside PostgreSQL, every index type available, and the non-obvious rules that govern when an index helps versus hurts.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;how-postgresql-stores-data-without-an-index&quot;&gt;How PostgreSQL Stores Data Without an Index&lt;/h2&gt;
&lt;p&gt;To understand indexes you have to understand what they replace. PostgreSQL stores table rows in &lt;strong&gt;heap files&lt;/strong&gt; — a collection of 8KB pages on disk. Rows are written in the order they arrive. There is no inherent sort order. There is no clustering. A row’s physical location is its &lt;strong&gt;TID (Tuple ID)&lt;/strong&gt; — a pair &lt;code&gt;(page_number, slot_offset)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When you run &lt;code&gt;SELECT * FROM orders WHERE user_id = 42&lt;/code&gt; against a table with no index, PostgreSQL has no choice but to read every page of the heap file, look at every row, and discard the ones where &lt;code&gt;user_id != 42&lt;/code&gt;. That’s a sequential scan. On a table with 10 million rows and 80,000 pages, that’s 80,000 page reads.&lt;/p&gt;
&lt;p&gt;An index is a separate data structure that maps column values to TIDs. Instead of reading 80,000 pages, you consult the index to find the handful of TIDs where &lt;code&gt;user_id = 42&lt;/code&gt;, then fetch just those heap pages. The index does not contain the full row — only the indexed column(s) and the TID pointer back to the heap.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;b-tree-internals-how-the-default-index-works&quot;&gt;B-tree Internals: How the Default Index Works&lt;/h2&gt;
&lt;p&gt;The default index type in PostgreSQL is a &lt;strong&gt;B-tree&lt;/strong&gt; (Balanced Tree). Understanding it deeply unlocks understanding of nearly everything else about index performance.&lt;/p&gt;
&lt;h3 id=&quot;the-structure&quot;&gt;The Structure&lt;/h3&gt;
&lt;p&gt;A B-tree index is a tree of fixed-size &lt;strong&gt;pages&lt;/strong&gt; (also 8KB, same as heap pages). There are three kinds of pages:&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 564 1105&quot;&gt;&lt;svg class=&quot;d2-1317245317 d2-svg&quot; width=&quot;564&quot; height=&quot;1105&quot; viewBox=&quot;-25 -25 564 1105&quot;&gt;&lt;rect x=&quot;-25.000000&quot; y=&quot;-25.000000&quot; width=&quot;564.000000&quot; height=&quot;1105.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-1317245317 .text-bold {
	font-family: &quot;d2-1317245317-font-bold&quot;;
}
@font-face {
	font-family: d2-1317245317-font-bold;
	src: url(&quot;data:application/font-woff;base64,d09GRgABAAAAAA3sAAoAAAAAFRAAAguFAAAAAAAAAAAAAAAAAAAAAAAAAABPUy8yAAAA9AAAAGAAAABgXxHXrmNtYXAAAAFUAAAAwgAAAQwmRyeMZ2x5ZgAAAhgAAAdKAAAJbKzyEpdoZWFkAAAJZAAAADYAAAA2G38e1GhoZWEAAAmcAAAAJAAAACQKfwXfaG10eAAACcAAAAB/AAAAgDwUBfRsb2NhAAAKQAAAAEIAAABCJ4glXG1heHAAAAqEAAAAIAAAACAAOAD3bmFtZQAACqQAAAMoAAAIKgjwVkFwb3N0AAANzAAAAB0AAAAg/9EAMgADAioCvAAFAAACigJYAAAASwKKAlgAAAFeADIBKQAAAgsHAwMEAwICBGAAAvcAAAADAAAAAAAAAABBREJPACAAIP//Au7/BgAAA9gBESAAAZ8AAAAAAfAClAAAACAAA3icjM49KzwAAMfxz/3v/h7P8/Pz3X6D0iW7RRkkmwwGWS5KRm+BZBdKeQEoGfBKLucFeAs/ubIZ/Jbf8hm+KCgqoKz0fWoqSsoqapbUrVi1Zt2GTVu27di1r+HQsZPqefUioa0X1S3/ovc0HDj60WnlMx9p5T0vec5THvOQ+7zlNXe5zXWucpmb5lnztN319xVMGzZi1JhxEyZN+aeo5L8OnWbM6tKtR6+yPv0GDBoyZ94CXwAAAP//AQAA//8gXTj1AAB4nGRWfWgb9xl+fz991fIl9kk6nWTrw7rTfUixZOtOd2fLlmXZspy4lmzHq5XEspOaxHPjfJE4ddbY22CBQNHIqEPIMlghNFAK+2MLG1tgY4zBFuh/2SgMxrKtlG6BNWzeBp0tjbtTEqf9wxycX7/P+z7P8z5nsME0AF7CN8ECLdAGLqAAZDJCcrIgsA5N1jSWtmgCIh3T2FW/954Qs8Zi1njX7fBbx4+j0iK+uXtmvrS09J/jAwP17//sQf3b6NIDAAwlADyJa+A0O8qS10t57HZWkCVVVdI8z7Kln558Z2b6xolEoG82mZztC+Ba4caFC++Mr4vVcvkoBwBI7wOPcQ0sRheytIVru2vme/QXXAOb+T5ClbYQxrXdpxsAz/B7cQ0I8LyEz1KkLClpHf7xwcvF4trYzMErw4MFXBOqU5NLPX9Eh1fk+Ises7gG+4He08PhZgWji2q2eTJ2sZBTbt7bnJnMZLOZSVzjjpQPLtD1/z15gk6kent5fQ8/AHbjGjj0TqwSoVjyw/vo8/u4fWNj96mJF29so9+hHfADC0AzvJJWNZ5nGbtDUFVZ8lIkK7B2uyapmmK3Ux7vLwrT17YwGwsPR5We1czx5StOa3j8FT/nLg+GiUqufKQtIvio14PRcxfrH8sB9iLtrjgPBH20gRdtbKM/ox3wQRjAxvA6oPpsy4jXK0sabbdb5LQ+AwqPXxwZPTMwvtBjxfWPnMWUoqb4xTv3hW5GJYbWDs+s5XKrBTfXosqRox0hlIkpPWBo6ANAa/ih/tR315owtMNYjqJkiiWPjYxEp0fD6fbOfR1EZ+joUbR51tapzKUJ+xmbLcKHLtW/BWABppHADrQDPTAAEwZLvJLWFGP25kOVJVqm2KbgjKAzJev0eex2i6kao79zNxVkeKPkn5nFvnF3Z5evI5ZZVLojP55ytKSPaMGwi4lNV18vbEwEBSEYFISYNCxwsj9CdGYfdfR1D4rWfWK4U2q3ugoHBqdEYrWV8fRPRJ1tXrdrYFSeSaKH8ZgQE8VYvL4V9dPtFovPHwia3OQb28iFfw5tpuKkTHq8sqTqxP92cmCLbLE57C6CI+ZfxezuR7QLobM2h/53uoBop+luWn5mENLYzkHmrzitXSVp5tBWsCsg+tDTXCixulD/EEVU0U/Xf9jU3+CyDTq/pL9d2MMU8ubOFwrnc7lzhcK5XCKZTCQTCSJ7+fDsWja7Nnv4cna9NJyfnMwPl8CcDd1AO+DaO1tTbXOyzkmeCjh9+/ztgawHPa1IKZvtG1ZrTKo/BgRUYxu9i3ZAMDgRNN2JRmYISaykXzSjPF46hCmP/VHqq/wIkwtHQsFkR2hAfOO1/kp4pCPd0d/Pd2VjKwQfrvo7aTfpdTuJaH9sbE7wHfF4BZ9/fyvbnxxdMLUgG9voHF7Tr93G8IrCKpom6+6knmuCoDpVmCTfWl9ng4TfSbs14vTcw7P2a9cu/SbO2a2rdsK8Za6xjZ7g69Da5Nacm/LovJr5xxgn7EWvLG9uLus/fpGmRb9P9PlE4oO7d+/du3v3g4vcYqVSZZhqpbLI6TMWAdAf8FUgAGRFvyZV1WRSpopvr6cPMmfW19H5eWfAs7uzbu4UAkAf4+sQ0OuHsClpM08MnR2qKssUN7NZTMUYzTfds1TILSoD1bRv0PvNr5Q230j0pISOKUmW5rPK+fOqxbah9/U2ttGf8HWIfVEjVnlmnGep5bE7KBPrX6WzbCFYFHv6AhNjc8Miz2ihie6lzNLXNFkbz68SkrgQiArRQMy70sNHuFDHMf7A/Gyq6LW2l4YGZg+YO9GNbfQYX9VT6yVsA9MdoVjH8+3+Wz7DjwQLYirT1x3ggiMutPK31givzfflTxNpbqGDk1K90n5XHOU31tvilULxZNrA6AZAn+CrsA9AHsJaRIlQ+y2Od+1McbD+V/RAG+XaraffvzO7cWz0zavf0Q1kMfL7U4NrAdLPL+pFKu2lwvLFHOIFww/IkTuZySW43nR1oHJaiiSH+04FhFg0GB8kuF5mUKQCGaJ7Ss5M+KyBg5I6FT8+lRz3Wv3lnDSdRF9P9HKJKCd0138viAEuSLqVYLwHMDCNbfSJ4ccYgNv0s2FC93MGVU2Py5dT4P3eqF92OzWmqzebWwiV29VAtD+K/YeC6mtS5kT/0LmxQ5fRj6R4kHm1P1UnkqEjrk6uMhGOxiujIyfk/NsX3vzuIUCQbAwhgB/omUALqiowDLvnKCZDfRmErZhVVV5KV39V9uS5AyKfnMgfvmJqXmmsoDj+tf79pEn9gyFTlUenTt22VMu7w2WzJtlYQahZY9yGTCaXlx/dLuNflnfeM2vmGnb4Cf6H/v8ETcrk3InPLZ/u+MzfeRuf4TxugRYAG1IQ7YhQERp11/+OvGO30HL9zi0StVpR69S1tWt6vdj4DM826wXdIoKGKJQt3qp/D526VUReUq+cqv/bCgD/BwAA//8BAAD//45Y5ucAAAABAAAAAguFG9rEqV8PPPUAAQPoAAAAANhdoIQAAAAA3WYvNv43/sQIbQPxAAEAAwACAAAAAAAAAAEAAAPY/u8AAAiY/jf+NwhtAAEAAAAAAAAAAAAAAAAAAAAgeJwEwK0NwlAYheH3HFFFwoeggKloSkLKpRNgrsHdBMFPF0B0BgQbMAyWBRiLxx/O/MBPig4UVxRfKH5QnNh4Tu+KTlfWrmnVkH0ke0+nN1lflnqxcLB1cHLQOKgdrBwkB72DVolBI3eNDJpx80Ttid0fAAD//wEAAP//6WEOPQAAAAAsACwAUABcAGwAjgC0AMYA/gEyAVgBwAHcAf4CKgJKAoYCrALYAvADHANaA4wDpgP0BDQEVARmBHgEhgSeBLYAAAABAAAAIACQAAwAYwAHAAEAAAAAAAAAAAAAAAAABAADeJyclM9uG1UUxn9ObNMKwQJFVbqJ7oJFkejYVEnVNiuH1IpFFAePC0JCSBPP+I8ynhl5Jg7hCVjzFrxFVzwEz4FYo/l87NgF0SaKknx37vnznXO+c4Ed/mabSvUh8Ec9MVxhr35ueIsH9RPD27TrW4arPKn9abhGWJsbrvN5rWf4I95WfzP8gP3qT4YfslttG/6YZ9Udw59sO/4y/Cn7vF3gCrzgV8MVdskMb7HDj4a3eYTFrFR5RNNwjc/YM1xnD+gzoSBmQsIIx5AJI66YEZHjEzFjwpCIEEeHFjGFviYEQo7Rf34N8CmYESjimAJHjE9MQM7YIv4ir5RzZRzqNLO7FgVjAi7kcUlAgiNlREpCxKXiFBRkvKJBg5yB+GYU5HjkTIjxSJkxokGXNqf0GTMhx9FWpJKZT8qQgmsC5XdmUXZmQERCbqyuSAjF04lfJO8Opzi6ZLJdj3y6EeFLHN/Ju+SWyvYrPP26NWabeZdsAubqZ6yuxLq51gTHui3ztvhWuOAV7l792WTy/h6F+l8o8gVXmn+oSSVikuDcLi18Kch3j3Ec6dzBV0e+p0OfE7q8oa9zix49WpzRp8Nr+Xbp4fiaLmccy6MjvLhrSzFn/IDjGzqyKWNH1p/FxCJ+JjN15+I4Ux1TMvW8ZO6p1kgV3n3C5Q6lG+rI5TPQHpWWTvNLtGcBI1NFJoZT9XKpjdz6F5oipqqlnO3tfbkNc9u95RbfkGqHS7UuOJWTWzB631S9dzRzrR+PgJCUC1kMSJnSoOBGvM8JuCLGcazunWhLClornzLPjVQSMRWDDonizMj0NzDd+MZ9sKF7Z29JKP+S6eWqqvtkcerV7YzeqHvLO9+6HK1NoGFTTdfUNBDXxLQfaafW+fvyzfW6pTzliJSY8F8vwDM8muxzwCFjZRjoZm6vQ1MvRJOXHKr6SyJZDaXnyCIc4PGcAw54yfN3+rhk4oyLW3FZz93imCO6HH5QFQv7Lke8Xn37/6y/i2lTtTierk4v7j3FJ3dQ6xfas9v3sqeJlZOYW7TbrTgjYFpycbvrNbnHeP8AAAD//wEAAP//9LdPUXicYmBmAIP/5xiMGLAAAAAAAP//AQAA//8vAQIDAAAA&quot;);
}
.d2-1317245317 .text-italic {
	font-family: &quot;d2-1317245317-font-italic&quot;;
}
@font-face {
	font-family: d2-1317245317-font-italic;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-1317245317 .fill-N1{fill:#0A0F25;}
		.d2-1317245317 .fill-N2{fill:#676C7E;}
		.d2-1317245317 .fill-N3{fill:#9499AB;}
		.d2-1317245317 .fill-N4{fill:#CFD2DD;}
		.d2-1317245317 .fill-N5{fill:#DEE1EB;}
		.d2-1317245317 .fill-N6{fill:#EEF1F8;}
		.d2-1317245317 .fill-N7{fill:#FFFFFF;}
		.d2-1317245317 .fill-B1{fill:#0D32B2;}
		.d2-1317245317 .fill-B2{fill:#0D32B2;}
		.d2-1317245317 .fill-B3{fill:#E3E9FD;}
		.d2-1317245317 .fill-B4{fill:#E3E9FD;}
		.d2-1317245317 .fill-B5{fill:#EDF0FD;}
		.d2-1317245317 .fill-B6{fill:#F7F8FE;}
		.d2-1317245317 .fill-AA2{fill:#4A6FF3;}
		.d2-1317245317 .fill-AA4{fill:#EDF0FD;}
		.d2-1317245317 .fill-AA5{fill:#F7F8FE;}
		.d2-1317245317 .fill-AB4{fill:#EDF0FD;}
		.d2-1317245317 .fill-AB5{fill:#F7F8FE;}
		.d2-1317245317 .stroke-N1{stroke:#0A0F25;}
		.d2-1317245317 .stroke-N2{stroke:#676C7E;}
		.d2-1317245317 .stroke-N3{stroke:#9499AB;}
		.d2-1317245317 .stroke-N4{stroke:#CFD2DD;}
		.d2-1317245317 .stroke-N5{stroke:#DEE1EB;}
		.d2-1317245317 .stroke-N6{stroke:#EEF1F8;}
		.d2-1317245317 .stroke-N7{stroke:#FFFFFF;}
		.d2-1317245317 .stroke-B1{stroke:#0D32B2;}
		.d2-1317245317 .stroke-B2{stroke:#0D32B2;}
		.d2-1317245317 .stroke-B3{stroke:#E3E9FD;}
		.d2-1317245317 .stroke-B4{stroke:#E3E9FD;}
		.d2-1317245317 .stroke-B5{stroke:#EDF0FD;}
		.d2-1317245317 .stroke-B6{stroke:#F7F8FE;}
		.d2-1317245317 .stroke-AA2{stroke:#4A6FF3;}
		.d2-1317245317 .stroke-AA4{stroke:#EDF0FD;}
		.d2-1317245317 .stroke-AA5{stroke:#F7F8FE;}
		.d2-1317245317 .stroke-AB4{stroke:#EDF0FD;}
		.d2-1317245317 .stroke-AB5{stroke:#F7F8FE;}
		.d2-1317245317 .background-color-N1{background-color:#0A0F25;}
		.d2-1317245317 .background-color-N2{background-color:#676C7E;}
		.d2-1317245317 .background-color-N3{background-color:#9499AB;}
		.d2-1317245317 .background-color-N4{background-color:#CFD2DD;}
		.d2-1317245317 .background-color-N5{background-color:#DEE1EB;}
		.d2-1317245317 .background-color-N6{background-color:#EEF1F8;}
		.d2-1317245317 .background-color-N7{background-color:#FFFFFF;}
		.d2-1317245317 .background-color-B1{background-color:#0D32B2;}
		.d2-1317245317 .background-color-B2{background-color:#0D32B2;}
		.d2-1317245317 .background-color-B3{background-color:#E3E9FD;}
		.d2-1317245317 .background-color-B4{background-color:#E3E9FD;}
		.d2-1317245317 .background-color-B5{background-color:#EDF0FD;}
		.d2-1317245317 .background-color-B6{background-color:#F7F8FE;}
		.d2-1317245317 .background-color-AA2{background-color:#4A6FF3;}
		.d2-1317245317 .background-color-AA4{background-color:#EDF0FD;}
		.d2-1317245317 .background-color-AA5{background-color:#F7F8FE;}
		.d2-1317245317 .background-color-AB4{background-color:#EDF0FD;}
		.d2-1317245317 .background-color-AB5{background-color:#F7F8FE;}
		.d2-1317245317 .color-N1{color:#0A0F25;}
		.d2-1317245317 .color-N2{color:#676C7E;}
		.d2-1317245317 .color-N3{color:#9499AB;}
		.d2-1317245317 .color-N4{color:#CFD2DD;}
		.d2-1317245317 .color-N5{color:#DEE1EB;}
		.d2-1317245317 .color-N6{color:#EEF1F8;}
		.d2-1317245317 .color-N7{color:#FFFFFF;}
		.d2-1317245317 .color-B1{color:#0D32B2;}
		.d2-1317245317 .color-B2{color:#0D32B2;}
		.d2-1317245317 .color-B3{color:#E3E9FD;}
		.d2-1317245317 .color-B4{color:#E3E9FD;}
		.d2-1317245317 .color-B5{color:#EDF0FD;}
		.d2-1317245317 .color-B6{color:#F7F8FE;}
		.d2-1317245317 .color-AA2{color:#4A6FF3;}
		.d2-1317245317 .color-AA4{color:#EDF0FD;}
		.d2-1317245317 .color-AA5{color:#F7F8FE;}
		.d2-1317245317 .color-AB4{color:#EDF0FD;}
		.d2-1317245317 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-1317245317);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-1317245317);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-1317245317);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-1317245317);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-1317245317);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-1317245317);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-1317245317);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-1317245317);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-1317245317);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-1317245317);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-1317245317);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-1317245317);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-1317245317);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-1317245317);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-1317245317);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-1317245317);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-1317245317);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-1317245317);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;Ug==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;116.000000&quot; y=&quot;0.000000&quot; width=&quot;144.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;188.000000&quot; y=&quot;38.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;188.000000&quot; dy=&quot;0.000000&quot;&gt;Root Page&lt;/tspan&gt;&lt;tspan x=&quot;188.000000&quot; dy=&quot;18.500000&quot;&gt;[50 | 150 | 300]&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;STE=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;324.000000&quot; y=&quot;182.000000&quot; width=&quot;139.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;393.500000&quot; y=&quot;220.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;393.500000&quot; dy=&quot;0.000000&quot;&gt;Internal Page&lt;/tspan&gt;&lt;tspan x=&quot;393.500000&quot; dy=&quot;18.500000&quot;&gt;[10 | 30 | 50]&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;STI=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;0.000000&quot; y=&quot;567.000000&quot; width=&quot;144.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;72.000000&quot; y=&quot;605.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;72.000000&quot; dy=&quot;0.000000&quot;&gt;Internal Page&lt;/tspan&gt;&lt;tspan x=&quot;72.000000&quot; dy=&quot;18.500000&quot;&gt;[80 | 120 | 150]&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;STM=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;112.000000&quot; y=&quot;182.000000&quot; width=&quot;152.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;188.000000&quot; y=&quot;220.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;188.000000&quot; dy=&quot;0.000000&quot;&gt;Internal Page&lt;/tspan&gt;&lt;tspan x=&quot;188.000000&quot; dy=&quot;18.500000&quot;&gt;[200 | 250 | 300]&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;TDE=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;380.000000&quot; y=&quot;364.000000&quot; width=&quot;134.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;447.000000&quot; y=&quot;402.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;447.000000&quot; dy=&quot;0.000000&quot;&gt;Leaf Page&lt;/tspan&gt;&lt;tspan x=&quot;447.000000&quot; dy=&quot;18.500000&quot;&gt;1, 5, 8 → TIDs&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;TDI=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;314.000000&quot; y=&quot;567.000000&quot; width=&quot;160.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;394.000000&quot; y=&quot;605.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;394.000000&quot; dy=&quot;0.000000&quot;&gt;Leaf Page&lt;/tspan&gt;&lt;tspan x=&quot;394.000000&quot; dy=&quot;18.500000&quot;&gt;15, 22, 30 → TIDs&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;TDM=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;298.000000&quot; y=&quot;770.000000&quot; width=&quot;161.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;378.500000&quot; y=&quot;808.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;378.500000&quot; dy=&quot;0.000000&quot;&gt;Leaf Page&lt;/tspan&gt;&lt;tspan x=&quot;378.500000&quot; dy=&quot;18.500000&quot;&gt;55, 70, 80 → TIDs&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;TDQ=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;144.000000&quot; y=&quot;973.000000&quot; width=&quot;177.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;232.500000&quot; y=&quot;1011.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;232.500000&quot; dy=&quot;0.000000&quot;&gt;Leaf Page&lt;/tspan&gt;&lt;tspan x=&quot;232.500000&quot; dy=&quot;18.500000&quot;&gt;90, 100, 120 → TIDs&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFIgLSZndDsgSTEpWzBd&quot;&gt;&lt;marker id=&quot;mk-d2-1317245317-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 261.330429 73.805935 C 366.700012 120.199997 393.500000 142.000000 393.500000 178.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1317245317-3488378134)&quot; mask=&quot;url(#d2-1317245317)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KFIgLSZndDsgSTIpWzBd&quot;&gt;&lt;path d=&quot;M 134.423951 83.231288 C 84.800003 122.000000 72.000000 150.199997 72.000000 177.500000 C 72.000000 204.800003 72.000000 241.199997 72.000000 268.500000 C 72.000000 295.799988 72.000000 332.200012 72.000000 359.500000 C 72.000000 386.799988 72.000000 518.700012 72.000000 563.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1317245317-3488378134)&quot; mask=&quot;url(#d2-1317245317)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KFIgLSZndDsgSTMpWzBd&quot;&gt;&lt;path d=&quot;M 188.000000 84.000000 C 188.000000 122.000000 188.000000 142.000000 188.000000 178.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1317245317-3488378134)&quot; mask=&quot;url(#d2-1317245317)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEkxIC0mZ3Q7IEwxKVswXQ==&quot;&gt;&lt;path d=&quot;M 419.003437 265.730062 C 441.200012 304.000000 447.000000 324.000000 447.000000 360.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1317245317-3488378134)&quot; mask=&quot;url(#d2-1317245317)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEkxIC0mZ3Q7IEwyKVswXQ==&quot;&gt;&lt;path d=&quot;M 324.036838 265.032025 C 259.350006 304.000000 242.750000 332.200012 242.750000 359.500000 C 242.750000 386.799988 260.549988 518.700012 328.450590 565.238608&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1317245317-3488378134)&quot; mask=&quot;url(#d2-1317245317)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEkyIC0mZ3Q7IEwzKVswXQ==&quot;&gt;&lt;path d=&quot;M 132.137579 649.648187 C 200.100006 697.299988 236.500000 721.700012 309.134135 768.338761&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1317245317-3488378134)&quot; mask=&quot;url(#d2-1317245317)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEkyIC0mZ3Q7IEw0KVswXQ==&quot;&gt;&lt;path d=&quot;M 67.804223 650.490395 C 63.200001 697.299988 62.000000 729.799988 62.000000 760.250000 C 62.000000 790.700012 82.199997 924.700012 159.576025 971.432055&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1317245317-3488378134)&quot; mask=&quot;url(#d2-1317245317)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEwxIC0mZ3Q7IEwyKVswXQ==&quot;&gt;&lt;marker id=&quot;mk-d2-1317245317-2177206569&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B2&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 447.000000 447.500000 C 447.000000 494.299988 440.600006 518.700012 416.858198 563.957811&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:6.000000,5.919384;&quot; marker-end=&quot;url(#mk-d2-1317245317-2177206569)&quot; mask=&quot;url(#d2-1317245317)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;442.500000&quot; y=&quot;515.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;←→&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEwyIC0mZ3Q7IEwzKVswXQ==&quot;&gt;&lt;path d=&quot;M 393.500000 650.500000 C 393.500000 697.299988 391.700012 721.700012 385.083845 766.542839&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:6.000000,5.919384;&quot; marker-end=&quot;url(#mk-d2-1317245317-2177206569)&quot; mask=&quot;url(#d2-1317245317)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;392.500000&quot; y=&quot;715.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;←→&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEwzIC0mZ3Q7IEw0KVswXQ==&quot;&gt;&lt;path d=&quot;M 378.250000 853.500000 C 378.250000 900.299988 361.049988 924.700012 295.512606 971.185826&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:6.000000,5.919384;&quot; marker-end=&quot;url(#mk-d2-1317245317-2177206569)&quot; mask=&quot;url(#d2-1317245317)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;358.500000&quot; y=&quot;932.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;←→&lt;/text&gt;&lt;/g&gt;&lt;mask id=&quot;d2-1317245317&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;564&quot; height=&quot;1105&quot;&gt;
&lt;rect x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;564&quot; height=&quot;1105&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;430.000000&quot; y=&quot;499.000000&quot; width=&quot;25&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;380.000000&quot; y=&quot;699.000000&quot; width=&quot;25&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;346.000000&quot; y=&quot;916.000000&quot; width=&quot;25&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Root page:&lt;/strong&gt; The entry point. Contains separator keys that route the search left or right.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Internal pages:&lt;/strong&gt; Branch nodes. Store separator keys and child page pointers. Never store TIDs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Leaf pages:&lt;/strong&gt; Store the actual index entries: &lt;code&gt;(indexed_value, TID)&lt;/code&gt; pairs sorted by value. Every leaf page is doubly linked to its neighbors — this is what makes range scans cheap.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;a-point-lookup-where-id--42&quot;&gt;A Point Lookup: &lt;code&gt;WHERE id = 42&lt;/code&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Read the root page. Binary search for 42 among separator keys. Follow the child pointer that covers 42’s range.&lt;/li&gt;
&lt;li&gt;Read the internal page. Binary search again. Follow the child pointer.&lt;/li&gt;
&lt;li&gt;Read the leaf page. Binary search for 42. Find the TID(s).&lt;/li&gt;
&lt;li&gt;Use the TID to fetch the actual row from the heap.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For a table with 10 million rows, a B-tree index is typically 3-4 levels deep. That’s 3-4 page reads to find any value — vs 80,000 for a seq scan. This is the O(log N) lookup.&lt;/p&gt;
&lt;h3 id=&quot;a-range-scan-where-id-between-100-and-200&quot;&gt;A Range Scan: &lt;code&gt;WHERE id BETWEEN 100 AND 200&lt;/code&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Find the leaf page containing 100 (same point lookup process).&lt;/li&gt;
&lt;li&gt;Scan forward across leaf pages (following the linked list) collecting TIDs until the value exceeds 200.&lt;/li&gt;
&lt;li&gt;Fetch heap rows for all collected TIDs.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The doubly-linked leaf chain makes this efficient — no need to go back to the root for each subsequent value. This is why B-trees support &lt;code&gt;ORDER BY&lt;/code&gt;, &lt;code&gt;BETWEEN&lt;/code&gt;, &lt;code&gt;&amp;#x3C;&lt;/code&gt;, &lt;code&gt;&gt;&lt;/code&gt; natively.&lt;/p&gt;
&lt;h3 id=&quot;page-splits--the-hidden-cost-of-inserts&quot;&gt;Page Splits — The Hidden Cost of Inserts&lt;/h3&gt;
&lt;p&gt;Every leaf page has a fill factor (default 90% for indexes). When a new index entry arrives and the target leaf page is full, PostgreSQL &lt;strong&gt;splits the page&lt;/strong&gt;: creates a new page, moves half the entries there, and updates the parent page to add a new separator key pointing to the new page.&lt;/p&gt;
&lt;p&gt;If the parent is also full, it splits too — a cascade that can propagate up to the root. Root splits increase the tree height by one. This is rare but means a B-tree grows in height slowly over time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why this matters for UUIDs&lt;/strong&gt; — we’ll cover this in depth later, but the short version is: random values cause every insert to land on a random page, requiring that page to be in the buffer cache. Monotonically increasing values always append to the rightmost leaf — only one page needs to be hot.&lt;/p&gt;
&lt;h3 id=&quot;the-visibility-map-and-index-only-scans&quot;&gt;The Visibility Map and Index-Only Scans&lt;/h3&gt;
&lt;p&gt;Every heap page has a corresponding bit in the &lt;strong&gt;visibility map&lt;/strong&gt; — a compact structure that tracks whether all rows on a page are visible to all transactions (fully frozen/vacuumed). When PostgreSQL does an index scan, it normally has to fetch the heap page to check row visibility. But if the visibility map says a page is all-visible, it can skip the heap fetch entirely and return the indexed values directly.&lt;/p&gt;
&lt;p&gt;This is an &lt;strong&gt;index-only scan&lt;/strong&gt; — the fastest possible read path. You see &lt;code&gt;Heap Fetches: 0&lt;/code&gt; in &lt;code&gt;EXPLAIN ANALYZE&lt;/code&gt; output. It requires:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;All &lt;code&gt;SELECT&lt;/code&gt;ed columns are in the index.&lt;/li&gt;
&lt;li&gt;The visibility map is current (i.e., &lt;code&gt;VACUUM&lt;/code&gt; has run recently on the table).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Tables with high write volume that haven’t been vacuumed recently will have many pages not marked all-visible, causing index-only scans to degrade back to regular index scans.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;index-types-in-postgresql&quot;&gt;Index Types in PostgreSQL&lt;/h2&gt;
&lt;p&gt;PostgreSQL has six built-in index types plus extensions, each optimized for different access patterns and data shapes.&lt;/p&gt;
&lt;h3 id=&quot;b-tree-default&quot;&gt;B-tree (Default)&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_orders_user_id&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders (user_id);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- equivalent to:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_orders_user_id&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;USING&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; btree (user_id);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Supports:&lt;/strong&gt; &lt;code&gt;=&lt;/code&gt;, &lt;code&gt;&amp;#x3C;&lt;/code&gt;, &lt;code&gt;&amp;#x3C;=&lt;/code&gt;, &lt;code&gt;&gt;&lt;/code&gt;, &lt;code&gt;&gt;=&lt;/code&gt;, &lt;code&gt;BETWEEN&lt;/code&gt;, &lt;code&gt;IN&lt;/code&gt;, &lt;code&gt;IS NULL&lt;/code&gt;, &lt;code&gt;IS NOT NULL&lt;/code&gt;, &lt;code&gt;LIKE &apos;prefix%&apos;&lt;/code&gt;, &lt;code&gt;ORDER BY&lt;/code&gt;, &lt;code&gt;DISTINCT&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Works with:&lt;/strong&gt; Any type that has a defined ordering — integers, text, timestamps, enums, UUIDs, numeric, etc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Use for:&lt;/strong&gt; Primary keys, foreign keys, range queries, sorting, prefix string matches. When in doubt, start here.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Does not support:&lt;/strong&gt; Full-text search, containment queries (&lt;code&gt;@&gt;&lt;/code&gt;), geometric overlap, JSONB key existence.&lt;/p&gt;
&lt;h3 id=&quot;hash&quot;&gt;Hash&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_orders_status_hash&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;USING&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; hash&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Computes a hash of the column value and stores &lt;code&gt;(hash_bucket, TID)&lt;/code&gt;. There is no tree — lookup is O(1) for equality.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Supports:&lt;/strong&gt; Only &lt;code&gt;=&lt;/code&gt; (equality). Nothing else.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Performance vs B-tree for equality:&lt;/strong&gt; Hash indexes are theoretically faster for pure equality lookups on high-cardinality columns. In practice, the difference is marginal — B-tree lookup is O(log N) but with a very small constant (3-4 page reads), and PostgreSQL’s buffer cache often keeps hot pages warm anyway.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Downsides:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cannot be used for &lt;code&gt;&amp;#x3C;&lt;/code&gt;, &lt;code&gt;&gt;&lt;/code&gt;, &lt;code&gt;BETWEEN&lt;/code&gt;, &lt;code&gt;ORDER BY&lt;/code&gt;, &lt;code&gt;LIKE&lt;/code&gt;, range anything.&lt;/li&gt;
&lt;li&gt;Cannot be used in a composite index.&lt;/li&gt;
&lt;li&gt;Before PostgreSQL 10, hash indexes were not WAL-logged and would be lost on crash — they had to be manually rebuilt. Since PostgreSQL 10 they are fully crash-safe, but the stigma remains in older documentation.&lt;/li&gt;
&lt;li&gt;The planner rarely chooses a hash index over a B-tree even for equality unless you force it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; Almost never in practice. The one valid use case is an equality-only lookup on a column with very long values (e.g., a SHA-256 hash column) where storing the full value in a B-tree entry is wasteful — a hash index stores only the hash of the hash, making index pages much denser. Even then, most engineers reach for B-tree and a &lt;code&gt;text_pattern_ops&lt;/code&gt; or just accept the slightly larger index.&lt;/p&gt;
&lt;h3 id=&quot;gin-generalized-inverted-index&quot;&gt;GIN (Generalized Inverted Index)&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_articles_tags&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; articles &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;USING&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; GIN (tags);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_products_attrs&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; products &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;USING&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; GIN (attributes);  &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- JSONB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_articles_fts&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; articles &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;USING&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; GIN (to_tsvector(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;english&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, body));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A GIN index is an &lt;strong&gt;inverted index&lt;/strong&gt; — it maps from individual element values to the rows that contain them. For an array column &lt;code&gt;tags = [&apos;go&apos;, &apos;performance&apos;, &apos;database&apos;]&lt;/code&gt;, the GIN index contains three entries: &lt;code&gt;go → {row 5, row 12, row 30}&lt;/code&gt;, &lt;code&gt;performance → {row 5, row 88}&lt;/code&gt;, etc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Supports:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Arrays: &lt;code&gt;@&gt;&lt;/code&gt; (contains), &lt;code&gt;&amp;#x3C;@&lt;/code&gt; (contained by), &lt;code&gt;&amp;#x26;&amp;#x26;&lt;/code&gt; (overlap), &lt;code&gt;= ANY()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;JSONB: &lt;code&gt;@&gt;&lt;/code&gt; (contains), &lt;code&gt;?&lt;/code&gt; (key exists), &lt;code&gt;?|&lt;/code&gt; (any key exists), &lt;code&gt;?&amp;#x26;&lt;/code&gt; (all keys exist)&lt;/li&gt;
&lt;li&gt;Full-text search: &lt;code&gt;@@&lt;/code&gt; (tsvector matches tsquery)&lt;/li&gt;
&lt;li&gt;Range types: with &lt;code&gt;range_ops&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Trigrams (with &lt;code&gt;pg_trgm&lt;/code&gt;): &lt;code&gt;LIKE &apos;%pattern%&apos;&lt;/code&gt;, &lt;code&gt;ILIKE&lt;/code&gt;, similarity (&lt;code&gt;%&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Characteristics:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lookup is very fast — find elements in O(log N), intersect posting lists.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Insert is expensive&lt;/strong&gt; — every new element in an array/JSONB must update potentially many posting lists. GIN uses a “pending list” buffer to batch writes (controlled by &lt;code&gt;gin_pending_list_limit&lt;/code&gt;), but the eventual merge is costly.&lt;/li&gt;
&lt;li&gt;Index size is large — an inverted index with many distinct elements can be several times larger than the source data.&lt;/li&gt;
&lt;li&gt;Not suitable for columns where every row has a unique value — there’s nothing to invert.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;The pending list:&lt;/strong&gt; GIN batches inserts into a pending list (default 4MB) and merges into the main index structure lazily (during &lt;code&gt;VACUUM&lt;/code&gt; or when the pending list fills). This makes individual inserts fast, but bulk loads can trigger expensive background merges. For bulk inserts, use &lt;code&gt;CREATE INDEX&lt;/code&gt; after loading rather than maintaining a GIN index during load.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Any array column you query with &lt;code&gt;&amp;#x26;&amp;#x26;&lt;/code&gt; or &lt;code&gt;@&gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;JSONB columns where you query by key existence or containment.&lt;/li&gt;
&lt;li&gt;Full-text search (&lt;code&gt;tsvector&lt;/code&gt; columns or &lt;code&gt;to_tsvector()&lt;/code&gt; expressions).&lt;/li&gt;
&lt;li&gt;Trigram search for &lt;code&gt;LIKE &apos;%substring%&apos;&lt;/code&gt; or fuzzy matching.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;gist-generalized-search-tree&quot;&gt;GiST (Generalized Search Tree)&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_locations_geom&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; locations &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;USING&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; gist (coordinates);  &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- PostGIS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_events_period&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; events &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;USING&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; gist (during);           &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- tsrange&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_articles_fts&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; articles &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;USING&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; gist (to_tsvector(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;english&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, body));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;GiST is a framework for building balanced search trees for non-standard data types. Where B-tree needs a total ordering, GiST needs only a set of user-defined predicates (consistent, union, penalty, picksplit). This makes it extensible to types that don’t have a natural linear order.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Supports:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Geometric types:&lt;/strong&gt; PostGIS (&lt;code&gt;geometry&lt;/code&gt;, &lt;code&gt;geography&lt;/code&gt;), built-in PostgreSQL geometric types (&lt;code&gt;point&lt;/code&gt;, &lt;code&gt;polygon&lt;/code&gt;, &lt;code&gt;circle&lt;/code&gt;). Operators: &lt;code&gt;&amp;#x26;&amp;#x26;&lt;/code&gt; (overlap), &lt;code&gt;@&gt;&lt;/code&gt; (contains), &lt;code&gt;~&lt;/code&gt; (same), &lt;code&gt;&amp;#x3C;-&gt;&lt;/code&gt; (distance).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Range types:&lt;/strong&gt; &lt;code&gt;int4range&lt;/code&gt;, &lt;code&gt;tsrange&lt;/code&gt;, &lt;code&gt;daterange&lt;/code&gt;, etc. Operators: &lt;code&gt;&amp;#x26;&amp;#x26;&lt;/code&gt;, &lt;code&gt;@&gt;&lt;/code&gt;, &lt;code&gt;-|-&lt;/code&gt; (adjacent).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Full-text search:&lt;/strong&gt; &lt;code&gt;tsvector @@ tsquery&lt;/code&gt; (but GIN is generally faster for this).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nearest-neighbor search:&lt;/strong&gt; GiST supports &lt;code&gt;ORDER BY column &amp;#x3C;-&gt; value LIMIT N&lt;/code&gt; — find the N closest points to a given coordinate. GIN cannot do this.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;GiST vs GIN for full-text:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GiST: faster to build, smaller index, supports &lt;code&gt;&amp;#x3C;-&gt;&lt;/code&gt; nearest-neighbor. Slower at search time.&lt;/li&gt;
&lt;li&gt;GIN: larger index, slower to build, much faster search (especially with many matching documents).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For read-heavy full-text search, GIN almost always wins. GiST is preferred when you need nearest-neighbor or when write performance matters more.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; Geospatial queries (PostGIS), date/time range overlap queries, nearest-neighbor lookups, exclusion constraints (&lt;code&gt;EXCLUDE USING gist&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id=&quot;brin-block-range-index&quot;&gt;BRIN (Block Range INdex)&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_logs_created_at&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; logs &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;USING&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; brin (created_at);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_logs_created_at&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; logs &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;USING&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; brin (created_at) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WITH&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (pages_per_range &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 64&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A BRIN index is radically different from everything else. Instead of indexing individual values, it divides the heap into &lt;strong&gt;ranges of consecutive pages&lt;/strong&gt; (default: 128 pages per range) and stores only the &lt;code&gt;min&lt;/code&gt; and &lt;code&gt;max&lt;/code&gt; value of the indexed column within that range.&lt;/p&gt;
&lt;p&gt;A BRIN index on a 100GB table might be only 256KB — tens of thousands of times smaller than a B-tree index on the same column.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How a lookup works:&lt;/strong&gt; For &lt;code&gt;WHERE created_at &gt; &apos;2025-01-01&apos;&lt;/code&gt;, scan the BRIN index (a tiny read) and discard any page ranges whose &lt;code&gt;max &amp;#x3C; &apos;2025-01-01&apos;&lt;/code&gt;. Then do a sequential scan of only the surviving page ranges. This is still a scan — BRIN doesn’t give you direct row-level access — but it skips huge chunks of the table.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The critical requirement: physical correlation.&lt;/strong&gt; BRIN only works when the physical order of rows in the heap matches the order of the indexed values. If you insert rows in timestamp order (which is natural for logs, events, IoT data), then page 1 has the oldest rows, page N has the newest — the min/max ranges are tight and exclusive. If rows are inserted randomly, the min/max of every range will be nearly the full column domain, and BRIN can’t skip anything.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Check physical correlation before creating a BRIN index&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; correlation &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pg_stats &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; tablename &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;logs&apos;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; attname &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;created_at&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- correlation near 1.0 = good for BRIN&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- correlation near 0.0 = BRIN will be useless&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Append-only or mostly-append tables (logs, events, time-series, audit trails).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;created_at&lt;/code&gt;, &lt;code&gt;inserted_at&lt;/code&gt;, serial IDs — any column that grows monotonically with insertion order.&lt;/li&gt;
&lt;li&gt;Very large tables (100GB+) where a B-tree index would be several GB itself.&lt;/li&gt;
&lt;li&gt;When you need only a small fraction of the table for a time-range query and can tolerate a scan of the relevant page ranges.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;When NOT to use:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Random insert patterns (correlation near 0) — BRIN will be ignored by the planner.&lt;/li&gt;
&lt;li&gt;High-selectivity point lookups — BRIN will still scan hundreds of pages; a B-tree is far better.&lt;/li&gt;
&lt;li&gt;Columns that are updated frequently — BRIN summaries can become stale (use &lt;code&gt;brin_summarize_new_values()&lt;/code&gt; or &lt;code&gt;autovacuum&lt;/code&gt; to refresh).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;sp-gist-space-partitioned-gist&quot;&gt;SP-GiST (Space-Partitioned GiST)&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_users_phone&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; users &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;USING&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; spgist (phone_number);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_network_cidr&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; networks &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;USING&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; spgist (&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;cidr&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;SP-GiST builds &lt;strong&gt;space-partitioned trees&lt;/strong&gt; — structures like tries, quad-trees, k-d trees, and radix trees. Unlike B-tree and GiST which are balanced, SP-GiST trees can be unbalanced and work well for data with natural partition structure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Supports:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Text prefix matching (trie structure) — similar to B-tree for &lt;code&gt;LIKE &apos;prefix%&apos;&lt;/code&gt; but faster on high-cardinality text.&lt;/li&gt;
&lt;li&gt;IP addresses and CIDR containment (&lt;code&gt;inet&lt;/code&gt;, &lt;code&gt;cidr&lt;/code&gt; types) — &lt;code&gt;&amp;#x3C;&amp;#x3C;&lt;/code&gt; (subnet), &lt;code&gt;&gt;&gt;=&lt;/code&gt; (supernet), etc.&lt;/li&gt;
&lt;li&gt;Geometric types (quad-tree for points) — 2D &lt;code&gt;&amp;#x26;&amp;#x26;&lt;/code&gt;, &lt;code&gt;@&gt;&lt;/code&gt;, &lt;code&gt;&amp;#x3C;-&gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Phone numbers and other hierarchically structured strings.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; IP/CIDR containment queries, text prefix queries on very long strings, 2D point data when GiST is too slow.&lt;/p&gt;
&lt;p&gt;In practice, SP-GiST is the most specialized index type and you’ll encounter it mainly when working with IP ranges, hierarchical codes, or specific geometric workloads.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;composite-indexes&quot;&gt;Composite Indexes&lt;/h2&gt;
&lt;p&gt;A composite (multi-column) index stores entries for multiple columns together.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_orders_user_status&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders (user_id, &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;the-prefix-rule&quot;&gt;The Prefix Rule&lt;/h3&gt;
&lt;p&gt;A composite index &lt;code&gt;(a, b, c)&lt;/code&gt; can be used by queries that filter on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;a&lt;/code&gt; alone&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a, b&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a, b, c&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But &lt;strong&gt;not&lt;/strong&gt; by queries that filter on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;b&lt;/code&gt; alone&lt;/li&gt;
&lt;li&gt;&lt;code&gt;c&lt;/code&gt; alone&lt;/li&gt;
&lt;li&gt;&lt;code&gt;b, c&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;c, a&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The planner can only use the index from the left. This is because the index is physically sorted first by &lt;code&gt;a&lt;/code&gt;, then by &lt;code&gt;b&lt;/code&gt; within each &lt;code&gt;a&lt;/code&gt; value, then by &lt;code&gt;c&lt;/code&gt; within each &lt;code&gt;(a, b)&lt;/code&gt; combination. Searching for &lt;code&gt;b = &apos;pending&apos;&lt;/code&gt; without knowing &lt;code&gt;a&lt;/code&gt; is equivalent to searching a phone book by first name — the sort order is useless.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- These use the index:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; user_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 42&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; user_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 42&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;pending&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; user_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 42&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;pending&apos;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;2025-01-01&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; user_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 42&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;2025-01-01&apos;&lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;  -- uses user_id part only&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- These do NOT use the index:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;pending&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;2025-01-01&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;pending&apos;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;2025-01-01&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Exception: index skip scan.&lt;/strong&gt; PostgreSQL 18+ (skip scans for skipping leading equality columns; not yet released as of this writing — verify against your target version) introduced skip scans for some cases, and even earlier versions can sometimes use a composite index for the second column alone via a bitmap scan — but you cannot rely on this.&lt;/p&gt;
&lt;h3 id=&quot;column-order-in-a-composite-index&quot;&gt;Column Order in a Composite Index&lt;/h3&gt;
&lt;p&gt;The rule of thumb: &lt;strong&gt;put equality conditions first, range conditions last&lt;/strong&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- GOOD: equality first, range last&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders (user_id, &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, created_at);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Query: WHERE user_id = 42 AND status = &apos;pending&apos; AND created_at &gt; &apos;2025-01-01&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Narrows to one user, one status, then scans the date range&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- BAD: range in the middle&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders (user_id, created_at, &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Query: WHERE user_id = 42 AND status = &apos;pending&apos; AND created_at &gt; &apos;2025-01-01&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- After a range condition (created_at BETWEEN ...), columns to its right (status)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- cannot be used as further index conditions — but they can still be applied as a&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- filter on the rows the index retrieves. The index is used; the filter just runs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- after the index lookup, post-fetching all rows that match the range.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Why? Once the index encounters a range predicate (&lt;code&gt;&gt;&lt;/code&gt;, &lt;code&gt;&amp;#x3C;&lt;/code&gt;, &lt;code&gt;BETWEEN&lt;/code&gt;, &lt;code&gt;LIKE &apos;x%&apos;&lt;/code&gt;), it can narrow to a start point but then must scan all subsequent entries. Columns after a range column in a composite index cannot be used to skip entries.&lt;/p&gt;
&lt;h3 id=&quot;covering-indexes-index-only-scans&quot;&gt;Covering Indexes (Index-Only Scans)&lt;/h3&gt;
&lt;p&gt;If you add the &lt;code&gt;SELECT&lt;/code&gt;ed columns to the index, PostgreSQL can serve the entire query from the index without touching the heap:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Query needs user_id (filter) and name, email (select)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Without this index: index scan + heap fetch per row&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- With this index: index-only scan (Heap Fetches: 0)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_users_covering&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; users (user_id) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;INCLUDE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, email);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;INCLUDE&lt;/code&gt; syntax (PostgreSQL 11+) adds columns to the leaf pages only — they’re not part of the sort key, so they don’t affect the tree structure or index lookups. The included columns just ride along as payload, allowing index-only scans without the filtering confusion of making them full key columns.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do not put frequently updated columns as key columns&lt;/strong&gt; in a composite index — every update to those columns requires updating the index entry, which means a page write + potential page split. Frequently updated columns work better in &lt;code&gt;INCLUDE&lt;/code&gt; (leaf-only) or in a separate index.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;partial-indexes&quot;&gt;Partial Indexes&lt;/h2&gt;
&lt;p&gt;A partial index indexes only the rows matching a &lt;code&gt;WHERE&lt;/code&gt; predicate.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Only index orders that aren&apos;t completed — active orders are the hot working set&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_orders_active&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders (user_id, created_at)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;completed&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Only index non-null values&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_users_referral&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; users (referral_code)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; referral_code &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;IS NOT NULL&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Unique constraint only on active users (allow multiple deleted users with same email)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; UNIQUE INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_users_email_active&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; users (email)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; deleted_at &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;IS&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; NULL&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Why partial indexes are powerful:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Smaller index.&lt;/strong&gt; If 95% of orders are &lt;code&gt;completed&lt;/code&gt; and you only ever query active orders, a partial index on the 5% that are active is 20x smaller, fits more in memory, and has faster tree traversal.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Better statistics.&lt;/strong&gt; The planner’s estimates for a partial index cover only the indexed subset — tighter statistics, better plan choices.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Conditional uniqueness.&lt;/strong&gt; You can enforce uniqueness only within a subset of rows (as in the email example above), which is impossible with a regular unique index.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;For a query to use a partial index, the query’s WHERE clause must imply the index predicate.&lt;/strong&gt; The planner must be able to prove that any row satisfying the query also satisfies the index’s WHERE clause.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Uses the partial index (query implies status != &apos;completed&apos;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; user_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 42&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;pending&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Does NOT use the partial index (query doesn&apos;t constrain status)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; user_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 42&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;uuids-and-indexes-the-fragmentation-problem&quot;&gt;UUIDs and Indexes: The Fragmentation Problem&lt;/h2&gt;
&lt;p&gt;This is one of the most important and commonly misunderstood topics in PostgreSQL performance.&lt;/p&gt;
&lt;h3 id=&quot;why-uuidv4-destroys-b-tree-performance&quot;&gt;Why UUIDv4 Destroys B-tree Performance&lt;/h3&gt;
&lt;p&gt;UUIDv4 values are random — &lt;code&gt;550e8400-e29b-41d4-a716-446655440000&lt;/code&gt; has no relationship to the UUID inserted before or after it. When you use UUIDv4 as a primary key (which creates a B-tree index), every insert goes to a &lt;strong&gt;random position&lt;/strong&gt; in the index tree.&lt;/p&gt;
&lt;p&gt;Here’s what happens at scale:&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 601 1184&quot;&gt;&lt;svg class=&quot;d2-48665031 d2-svg&quot; width=&quot;601&quot; height=&quot;1184&quot; viewBox=&quot;-5 -9 601 1184&quot;&gt;&lt;rect x=&quot;-5.000000&quot; y=&quot;-9.000000&quot; width=&quot;601.000000&quot; height=&quot;1184.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-48665031 .text {
	font-family: &quot;d2-48665031-font-regular&quot;;
}
@font-face {
	font-family: d2-48665031-font-regular;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-48665031 .text-bold {
	font-family: &quot;d2-48665031-font-bold&quot;;
}
@font-face {
	font-family: d2-48665031-font-bold;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-48665031 .fill-N1{fill:#0A0F25;}
		.d2-48665031 .fill-N2{fill:#676C7E;}
		.d2-48665031 .fill-N3{fill:#9499AB;}
		.d2-48665031 .fill-N4{fill:#CFD2DD;}
		.d2-48665031 .fill-N5{fill:#DEE1EB;}
		.d2-48665031 .fill-N6{fill:#EEF1F8;}
		.d2-48665031 .fill-N7{fill:#FFFFFF;}
		.d2-48665031 .fill-B1{fill:#0D32B2;}
		.d2-48665031 .fill-B2{fill:#0D32B2;}
		.d2-48665031 .fill-B3{fill:#E3E9FD;}
		.d2-48665031 .fill-B4{fill:#E3E9FD;}
		.d2-48665031 .fill-B5{fill:#EDF0FD;}
		.d2-48665031 .fill-B6{fill:#F7F8FE;}
		.d2-48665031 .fill-AA2{fill:#4A6FF3;}
		.d2-48665031 .fill-AA4{fill:#EDF0FD;}
		.d2-48665031 .fill-AA5{fill:#F7F8FE;}
		.d2-48665031 .fill-AB4{fill:#EDF0FD;}
		.d2-48665031 .fill-AB5{fill:#F7F8FE;}
		.d2-48665031 .stroke-N1{stroke:#0A0F25;}
		.d2-48665031 .stroke-N2{stroke:#676C7E;}
		.d2-48665031 .stroke-N3{stroke:#9499AB;}
		.d2-48665031 .stroke-N4{stroke:#CFD2DD;}
		.d2-48665031 .stroke-N5{stroke:#DEE1EB;}
		.d2-48665031 .stroke-N6{stroke:#EEF1F8;}
		.d2-48665031 .stroke-N7{stroke:#FFFFFF;}
		.d2-48665031 .stroke-B1{stroke:#0D32B2;}
		.d2-48665031 .stroke-B2{stroke:#0D32B2;}
		.d2-48665031 .stroke-B3{stroke:#E3E9FD;}
		.d2-48665031 .stroke-B4{stroke:#E3E9FD;}
		.d2-48665031 .stroke-B5{stroke:#EDF0FD;}
		.d2-48665031 .stroke-B6{stroke:#F7F8FE;}
		.d2-48665031 .stroke-AA2{stroke:#4A6FF3;}
		.d2-48665031 .stroke-AA4{stroke:#EDF0FD;}
		.d2-48665031 .stroke-AA5{stroke:#F7F8FE;}
		.d2-48665031 .stroke-AB4{stroke:#EDF0FD;}
		.d2-48665031 .stroke-AB5{stroke:#F7F8FE;}
		.d2-48665031 .background-color-N1{background-color:#0A0F25;}
		.d2-48665031 .background-color-N2{background-color:#676C7E;}
		.d2-48665031 .background-color-N3{background-color:#9499AB;}
		.d2-48665031 .background-color-N4{background-color:#CFD2DD;}
		.d2-48665031 .background-color-N5{background-color:#DEE1EB;}
		.d2-48665031 .background-color-N6{background-color:#EEF1F8;}
		.d2-48665031 .background-color-N7{background-color:#FFFFFF;}
		.d2-48665031 .background-color-B1{background-color:#0D32B2;}
		.d2-48665031 .background-color-B2{background-color:#0D32B2;}
		.d2-48665031 .background-color-B3{background-color:#E3E9FD;}
		.d2-48665031 .background-color-B4{background-color:#E3E9FD;}
		.d2-48665031 .background-color-B5{background-color:#EDF0FD;}
		.d2-48665031 .background-color-B6{background-color:#F7F8FE;}
		.d2-48665031 .background-color-AA2{background-color:#4A6FF3;}
		.d2-48665031 .background-color-AA4{background-color:#EDF0FD;}
		.d2-48665031 .background-color-AA5{background-color:#F7F8FE;}
		.d2-48665031 .background-color-AB4{background-color:#EDF0FD;}
		.d2-48665031 .background-color-AB5{background-color:#F7F8FE;}
		.d2-48665031 .color-N1{color:#0A0F25;}
		.d2-48665031 .color-N2{color:#676C7E;}
		.d2-48665031 .color-N3{color:#9499AB;}
		.d2-48665031 .color-N4{color:#CFD2DD;}
		.d2-48665031 .color-N5{color:#DEE1EB;}
		.d2-48665031 .color-N6{color:#EEF1F8;}
		.d2-48665031 .color-N7{color:#FFFFFF;}
		.d2-48665031 .color-B1{color:#0D32B2;}
		.d2-48665031 .color-B2{color:#0D32B2;}
		.d2-48665031 .color-B3{color:#E3E9FD;}
		.d2-48665031 .color-B4{color:#E3E9FD;}
		.d2-48665031 .color-B5{color:#EDF0FD;}
		.d2-48665031 .color-B6{color:#F7F8FE;}
		.d2-48665031 .color-AA2{color:#4A6FF3;}
		.d2-48665031 .color-AA4{color:#EDF0FD;}
		.d2-48665031 .color-AA5{color:#F7F8FE;}
		.d2-48665031 .color-AB4{color:#EDF0FD;}
		.d2-48665031 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-48665031);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-48665031);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-48665031);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-48665031);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-48665031);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-48665031);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-48665031);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-48665031);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-48665031);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-48665031);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-48665031);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-48665031);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-48665031);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-48665031);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-48665031);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-48665031);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-48665031);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-48665031);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;dXVpZHY0&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;20.000000&quot; y=&quot;56.000000&quot; width=&quot;520.000000&quot; height=&quot;504.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#E3E9FD&quot; class=&quot;stroke-B1 fill-B4&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;280.000000&quot; y=&quot;43.000000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:28px&quot;&gt;UUIDv4 (random) inserts&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;dXVpZHY3&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;21.000000&quot; y=&quot;646.000000&quot; width=&quot;550.000000&quot; height=&quot;504.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#E3E9FD&quot; class=&quot;stroke-B1 fill-B4&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;296.000000&quot; y=&quot;633.000000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:28px&quot;&gt;UUIDv7 (time-ordered) inserts&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;dXVpZHY0LkE=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;51.000000&quot; y=&quot;86.000000&quot; width=&quot;145.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;123.500000&quot; y=&quot;124.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Insert abc12...&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;dXVpZHY0LkI=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;52.000000&quot; y=&quot;212.000000&quot; width=&quot;142.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;123.000000&quot; y=&quot;250.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Insert f7e3a...&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;dXVpZHY0LkM=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;50.000000&quot; y=&quot;338.000000&quot; width=&quot;146.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;123.000000&quot; y=&quot;376.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Insert 2b9dc...&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;dXVpZHY0LkQ=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;52.000000&quot; y=&quot;464.000000&quot; width=&quot;142.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;123.000000&quot; y=&quot;502.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Insert 88fa1...&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;dXVpZHY0LlAx&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;327.000000&quot; y=&quot;86.000000&quot; width=&quot;183.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;418.500000&quot; y=&quot;124.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Random page 4,821&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;dXVpZHY0LlAy&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;334.000000&quot; y=&quot;212.000000&quot; width=&quot;169.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;418.500000&quot; y=&quot;250.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Random page 192&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;dXVpZHY0LlAz&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;327.000000&quot; y=&quot;338.000000&quot; width=&quot;183.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;418.500000&quot; y=&quot;376.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Random page 7,043&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;dXVpZHY0LlA0&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;327.000000&quot; y=&quot;464.000000&quot; width=&quot;183.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;418.500000&quot; y=&quot;502.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Random page 1,156&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;dXVpZHY3LkU=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;51.000000&quot; y=&quot;676.000000&quot; width=&quot;145.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;123.500000&quot; y=&quot;714.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Insert 018e1...&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;dXVpZHY3LkY=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;51.000000&quot; y=&quot;802.000000&quot; width=&quot;145.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;123.500000&quot; y=&quot;840.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Insert 018e2...&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;dXVpZHY3Lkc=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;51.000000&quot; y=&quot;928.000000&quot; width=&quot;145.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;123.500000&quot; y=&quot;966.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Insert 018e3...&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;dXVpZHY3Lkg=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;51.000000&quot; y=&quot;1054.000000&quot; width=&quot;145.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;123.500000&quot; y=&quot;1092.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Insert 018e4...&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;dXVpZHY3LlA1&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;344.000000&quot; y=&quot;676.000000&quot; width=&quot;149.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;418.500000&quot; y=&quot;714.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Rightmost leaf&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;dXVpZHY3LlA2&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;344.000000&quot; y=&quot;802.000000&quot; width=&quot;149.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;418.500000&quot; y=&quot;840.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Rightmost leaf&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;dXVpZHY3LlA3&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;296.000000&quot; y=&quot;928.000000&quot; width=&quot;245.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;418.500000&quot; y=&quot;966.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Rightmost leaf (or new split)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;dXVpZHY3LlA4&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;344.000000&quot; y=&quot;1054.000000&quot; width=&quot;149.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;418.500000&quot; y=&quot;1092.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Rightmost leaf&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;dXVpZHY0LihBIC0mZ3Q7IFAxKVswXQ==&quot;&gt;&lt;marker id=&quot;mk-d2-48665031-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 198.500000 119.000000 C 236.100006 119.000000 262.200012 119.000000 323.000000 119.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-48665031-3488378134)&quot; mask=&quot;url(#d2-48665031)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;dXVpZHY0LihCIC0mZ3Q7IFAyKVswXQ==&quot;&gt;&lt;path d=&quot;M 196.000000 245.000000 C 235.600006 245.000000 263.600006 245.000000 330.000000 245.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-48665031-3488378134)&quot; mask=&quot;url(#d2-48665031)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;dXVpZHY0LihDIC0mZ3Q7IFAzKVswXQ==&quot;&gt;&lt;path d=&quot;M 198.000000 371.000000 C 236.000000 371.000000 262.200012 371.000000 323.000000 371.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-48665031-3488378134)&quot; mask=&quot;url(#d2-48665031)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;dXVpZHY0LihEIC0mZ3Q7IFA0KVswXQ==&quot;&gt;&lt;path d=&quot;M 196.000000 497.000000 C 235.600006 497.000000 262.200012 497.000000 323.000000 497.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-48665031-3488378134)&quot; mask=&quot;url(#d2-48665031)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;dXVpZHY3LihFIC0mZ3Q7IFA1KVswXQ==&quot;&gt;&lt;path d=&quot;M 198.500000 709.000000 C 236.100006 709.000000 265.600006 709.000000 340.000000 709.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-48665031-3488378134)&quot; mask=&quot;url(#d2-48665031)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;dXVpZHY3LihGIC0mZ3Q7IFA2KVswXQ==&quot;&gt;&lt;path d=&quot;M 198.500000 835.000000 C 236.100006 835.000000 265.600006 835.000000 340.000000 835.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-48665031-3488378134)&quot; mask=&quot;url(#d2-48665031)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;dXVpZHY3LihHIC0mZ3Q7IFA3KVswXQ==&quot;&gt;&lt;path d=&quot;M 198.500000 961.000000 C 236.100006 961.000000 256.000000 961.000000 292.000000 961.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-48665031-3488378134)&quot; mask=&quot;url(#d2-48665031)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;dXVpZHY3LihIIC0mZ3Q7IFA4KVswXQ==&quot;&gt;&lt;path d=&quot;M 198.500000 1087.000000 C 236.100006 1087.000000 265.600006 1087.000000 340.000000 1087.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-48665031-3488378134)&quot; mask=&quot;url(#d2-48665031)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;mask id=&quot;d2-48665031&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-5&quot; y=&quot;-9&quot; width=&quot;601&quot; height=&quot;1184&quot;&gt;
&lt;rect x=&quot;-5&quot; y=&quot;-9&quot; width=&quot;601&quot; height=&quot;1184&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;

&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;The cascade of problems:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cache thrash.&lt;/strong&gt; Each insert touches a different random leaf page. On a large table, the entire leaf level of the index is larger than your buffer cache (&lt;code&gt;shared_buffers&lt;/code&gt; is the chunk of RAM Postgres reserves as a database-wide page cache; default 128 MB, typically tuned to ~25% of system memory). Every insert requires reading a cold page from disk before writing to it — a random read + a dirty write per insert.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Index bloat.&lt;/strong&gt; Because inserts land on random pages, leaf pages fill up and split uniformly across the entire key space. After a split, both resulting pages are around 50% full. On a sequential insert pattern, the rightmost page is the only one that fills and splits — everything else stays at 90%+ fill factor. With random UUIDs, average fill factor degrades toward 70-75%, making the index ~25% larger than necessary.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;WAL amplification.&lt;/strong&gt; Every random page touched must be written to WAL. Sequential inserts touch one hot page repeatedly — the WAL entry for a page write is amortized across many inserts. Random inserts each dirty a new page.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Write latency spikes.&lt;/strong&gt; Under high insert volume, the buffer eviction pressure from constantly loading new random pages causes latency spikes as the OS does I/O. This is most visible on spinning disks but happens on SSDs too.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;How bad is it in practice?&lt;/strong&gt; On a table of 50 million rows with a UUIDv4 primary key:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Index size: ~3GB (B-tree on 16-byte UUID × 50M rows, with bloat)&lt;/li&gt;
&lt;li&gt;Insert throughput: drops significantly compared to serial/BIGSERIAL as the table grows&lt;/li&gt;
&lt;li&gt;The working set of “hot index pages” = the entire leaf level ≈ the entire 3GB index&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With a BIGSERIAL primary key (sequential integers):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Index size: ~800MB (8-byte integers, no bloat — rightmost leaf stays hot)&lt;/li&gt;
&lt;li&gt;Insert throughput: stable as the table grows — only the rightmost leaf + its path to root need to be hot&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;the-fixes&quot;&gt;The Fixes&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Option 1: Use BIGSERIAL / BIGINT instead of UUID&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The simplest fix. A 64-bit integer primary key is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Half the size per row (8 bytes vs 16 bytes)&lt;/li&gt;
&lt;li&gt;Always sequential — no fragmentation&lt;/li&gt;
&lt;li&gt;Faster for equality lookups (smaller comparison)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Downside: exposes sequential IDs in URLs/APIs (enumeration risk), coordination complexity in distributed systems.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option 2: UUIDv7 (time-ordered UUID)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;UUIDv7 encodes a millisecond-precision timestamp in the most significant bits:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;018e3c2f-1234-7xxx-xxxx-xxxxxxxxxxxx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;^^^^^^^^^&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;timestamp prefix (48 bits, ms precision)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because the timestamp prefix increases monotonically, UUIDv7 inserts always go to the rightmost leaf of the B-tree — exactly like sequential integers. You get global uniqueness without coordination, URL-safe IDs, and no B-tree fragmentation.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- gen_random_uuid() has been in core PostgreSQL since 13 (and in pgcrypto long&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- before). For UUIDv7 specifically, use the pg_uuidv7 extension or generate at&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- the application layer.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; EXTENSION pg_uuidv7;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; uuid_generate_v7();  &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- 018e3c2f-1234-7abc-...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Or generate in application code (most UUID libraries support v7 now)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Option 3: ULID&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Universally Unique Lexicographically Sortable Identifier — 128-bit, 26-character Crockford Base32 string. The first 48 bits are a millisecond timestamp, the remaining 80 bits are random. Same properties as UUIDv7: monotonically increasing within a millisecond, globally unique, B-tree friendly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option 4: Keep UUIDv4 but use &lt;code&gt;fillfactor&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;FILLFACTOR&lt;/strong&gt; (the percentage of each index/heap page Postgres fills before considering it ‘full’ — default is 90 for indexes, 100 for heap tables; lowering it leaves room for HOT updates and reduces page splits on write-heavy tables).&lt;/p&gt;
&lt;p&gt;If you must keep UUIDv4 (e.g., existing system, external ID requirements), reduce the index fill factor to leave room for out-of-order inserts without triggering as many splits:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_orders_uuid&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders (id) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WITH&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (fillfactor &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 70&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This trades index size (larger, less dense pages) for fewer splits. It doesn’t fix cache thrash — random pages are still loaded cold for each insert — but reduces write amplification from constant splits.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt;&lt;/p&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;PK Type&lt;/th&gt;&lt;th&gt;Insert pattern&lt;/th&gt;&lt;th&gt;B-tree behavior&lt;/th&gt;&lt;th&gt;Recommended?&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;BIGSERIAL&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Sequential&lt;/td&gt;&lt;td&gt;Rightmost-leaf only, no bloat&lt;/td&gt;&lt;td&gt;Yes — for internal systems&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;UUIDv4&lt;/td&gt;&lt;td&gt;Random&lt;/td&gt;&lt;td&gt;Full-tree random access, ~25% bloat&lt;/td&gt;&lt;td&gt;Avoid for high-write tables&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;UUIDv7 / ULID&lt;/td&gt;&lt;td&gt;Monotonic (by time)&lt;/td&gt;&lt;td&gt;Rightmost-leaf only, like BIGSERIAL&lt;/td&gt;&lt;td&gt;Yes — for distributed/external IDs&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;UUIDv1&lt;/td&gt;&lt;td&gt;Random in B-tree key order&lt;/td&gt;&lt;td&gt;Fragments like UUIDv4&lt;/td&gt;&lt;td&gt;Avoid — see note below&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Note on UUIDv1:&lt;/strong&gt; Despite being timestamp-based, UUIDv1’s time bits are stored &lt;em&gt;low-order-first&lt;/em&gt; — so it sorts roughly randomly in B-tree key order and fragments leaves like UUIDv4. UUIDv1 also leaks the host MAC address. UUIDv6 reorders v1’s bits to be monotonic but is rarely used; UUIDv7 is the right modern choice.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;data-types-and-index-compatibility&quot;&gt;Data Types and Index Compatibility&lt;/h2&gt;
&lt;p&gt;Not every data type works well with every index type. Here’s the full picture.&lt;/p&gt;
&lt;h3 id=&quot;operator-classes&quot;&gt;Operator Classes&lt;/h3&gt;
&lt;p&gt;PostgreSQL links data types to index types via &lt;strong&gt;operator classes&lt;/strong&gt;. An operator class defines which operators the index can answer for a given type. When you create an index, you can specify the operator class explicitly:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Default operator class for text (uses locale-aware collation)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; users (last_name);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- text_pattern_ops: ignores collation, supports LIKE &apos;prefix%&apos; and pattern matching&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Required for LIKE queries that need to use an index with non-C locale&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; users (last_name text_pattern_ops);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If your database locale is not &lt;code&gt;C&lt;/code&gt; or &lt;code&gt;POSIX&lt;/code&gt;, a regular B-tree index on a text column &lt;strong&gt;cannot support &lt;code&gt;LIKE &apos;prefix%&apos;&lt;/code&gt;&lt;/strong&gt; — you need &lt;code&gt;text_pattern_ops&lt;/code&gt;. This surprises many engineers who add an index on &lt;code&gt;email&lt;/code&gt; and then find their &lt;code&gt;WHERE email LIKE &apos;john%&apos;&lt;/code&gt; query still does a seq scan.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Check your database locale&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;SHOW lc_collate;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- If not &apos;C&apos; or &apos;POSIX&apos;, use text_pattern_ops for LIKE support&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Correct approach for pattern matching on non-C locale:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_users_email_pattern&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; users (email text_pattern_ops);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; users &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; email &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;LIKE&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;john%&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;  &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- now uses the index&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;type-to-index-quick-reference&quot;&gt;Type-to-Index Quick Reference&lt;/h3&gt;





















































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Data Type&lt;/th&gt;&lt;th&gt;Best Index&lt;/th&gt;&lt;th&gt;Notes&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;integer&lt;/code&gt;, &lt;code&gt;bigint&lt;/code&gt;, &lt;code&gt;numeric&lt;/code&gt;&lt;/td&gt;&lt;td&gt;B-tree&lt;/td&gt;&lt;td&gt;Default. Full range/equality/order support.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;text&lt;/code&gt;, &lt;code&gt;varchar&lt;/code&gt;&lt;/td&gt;&lt;td&gt;B-tree&lt;/td&gt;&lt;td&gt;Use &lt;code&gt;text_pattern_ops&lt;/code&gt; for &lt;code&gt;LIKE&lt;/code&gt; on non-C locale.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;text&lt;/code&gt; (substring/fuzzy)&lt;/td&gt;&lt;td&gt;GIN + &lt;code&gt;pg_trgm&lt;/code&gt;&lt;/td&gt;&lt;td&gt;For &lt;code&gt;LIKE &apos;%middle%&apos;&lt;/code&gt;, &lt;code&gt;ILIKE&lt;/code&gt;, similarity.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;uuid&lt;/code&gt;&lt;/td&gt;&lt;td&gt;B-tree&lt;/td&gt;&lt;td&gt;Works. Random UUIDv4 causes fragmentation — use UUIDv7.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;timestamp&lt;/code&gt;, &lt;code&gt;timestamptz&lt;/code&gt;&lt;/td&gt;&lt;td&gt;B-tree&lt;/td&gt;&lt;td&gt;Full range support. BRIN if append-only large table.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;date&lt;/code&gt;&lt;/td&gt;&lt;td&gt;B-tree&lt;/td&gt;&lt;td&gt;Same as timestamp.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;boolean&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Partial index&lt;/td&gt;&lt;td&gt;A plain B-tree on a boolean column has only two distinct values, so it can’t narrow a query much on its own. Use a &lt;strong&gt;partial index&lt;/strong&gt; (&lt;code&gt;WHERE active = true&lt;/code&gt;) to index only the rows that matter, or include the boolean as a leading or trailing column of a composite index.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;enum&lt;/code&gt;&lt;/td&gt;&lt;td&gt;B-tree&lt;/td&gt;&lt;td&gt;Equality and ordering works. Low cardinality — partial index often better.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;jsonb&lt;/code&gt;&lt;/td&gt;&lt;td&gt;GIN&lt;/td&gt;&lt;td&gt;&lt;code&gt;@&gt;&lt;/code&gt;, &lt;code&gt;?&lt;/code&gt;, `?&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;text[]&lt;/code&gt;, &lt;code&gt;int[]&lt;/code&gt; (arrays)&lt;/td&gt;&lt;td&gt;GIN&lt;/td&gt;&lt;td&gt;&lt;code&gt;@&gt;&lt;/code&gt;, &lt;code&gt;&amp;#x26;&amp;#x26;&lt;/code&gt;, &lt;code&gt;= ANY()&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;tsvector&lt;/code&gt;&lt;/td&gt;&lt;td&gt;GIN&lt;/td&gt;&lt;td&gt;Full-text &lt;code&gt;@@&lt;/code&gt;. GiST if nearest-neighbor needed.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;geometry&lt;/code&gt; (PostGIS)&lt;/td&gt;&lt;td&gt;GiST&lt;/td&gt;&lt;td&gt;Spatial operators (&lt;code&gt;&amp;#x26;&amp;#x26;&lt;/code&gt;, &lt;code&gt;@&gt;&lt;/code&gt;, &lt;code&gt;&amp;#x3C;-&gt;&lt;/code&gt;).&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;tsrange&lt;/code&gt;, &lt;code&gt;daterange&lt;/code&gt;&lt;/td&gt;&lt;td&gt;GiST&lt;/td&gt;&lt;td&gt;Range overlap &lt;code&gt;&amp;#x26;&amp;#x26;&lt;/code&gt;, containment &lt;code&gt;@&gt;&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;inet&lt;/code&gt;, &lt;code&gt;cidr&lt;/code&gt;&lt;/td&gt;&lt;td&gt;SP-GiST&lt;/td&gt;&lt;td&gt;Subnet containment &lt;code&gt;&amp;#x3C;&amp;#x3C;&lt;/code&gt;, &lt;code&gt;&gt;&gt;=&lt;/code&gt;. B-tree for exact equality.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;hstore&lt;/code&gt;&lt;/td&gt;&lt;td&gt;GIN&lt;/td&gt;&lt;td&gt;Key existence, containment.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3 id=&quot;low-cardinality-columns-when-b-tree-is-counterproductive&quot;&gt;Low-Cardinality Columns: When B-tree Is Counterproductive&lt;/h3&gt;
&lt;p&gt;A &lt;strong&gt;low-cardinality&lt;/strong&gt; column has very few distinct values — &lt;code&gt;boolean&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt; with 3-4 values, &lt;code&gt;country_code&lt;/code&gt; with ~250 values.&lt;/p&gt;
&lt;p&gt;A B-tree index on &lt;code&gt;status = &apos;pending&apos;&lt;/code&gt; where 30% of rows are pending: the index will return 30% of all rows. PostgreSQL’s planner knows this and will likely choose a seq scan instead (since 30% &gt; the ~15% threshold for preferring a seq scan). The index exists but is rarely used.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What works instead:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Partial index: only the rows you actually query&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_orders_pending&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders (created_at) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;pending&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- This index is tiny (only pending rows), always selective, always used for pending queries&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Composite index with high-cardinality leading column&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_orders_user_status&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders (user_id, &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- user_id is high-cardinality — user_id narrows to a manageable set, status filters further&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;jsonb-indexing-choosing-the-right-approach&quot;&gt;JSONB Indexing: Choosing the Right Approach&lt;/h3&gt;
&lt;p&gt;JSONB is one of the most commonly over-indexed or wrongly-indexed types. There are three different approaches with very different trade-offs:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- 1. GIN index on the whole column — supports @&gt;, ?, ?|, ?&amp;#x26;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;--    Large index, good for existence/containment queries&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_products_attrs_gin&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; products &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;USING&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; GIN (attributes);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; products &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; attributes @&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;{&quot;color&quot;: &quot;red&quot;}&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;  &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- uses GIN&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- 2. Functional B-tree index on a specific key — supports = and range on that key&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;--    Small index, only for that specific key, supports ordering&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_products_color&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; products ((attributes&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;color&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; products &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; attributes&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;color&apos;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;red&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;  &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- uses B-tree&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; products &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ORDER BY&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; attributes&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;price&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;numeric&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;  &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- uses B-tree for sort&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- 3. GIN with jsonb_path_ops — smaller than default GIN, faster @&gt; queries&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;--    But ONLY supports @&gt;, not ?, ?|, ?&amp;#x26;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_products_attrs_path&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; products &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;USING&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; GIN (attributes jsonb_path_ops);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; products &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; attributes @&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;{&quot;color&quot;: &quot;red&quot;}&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;  &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- uses GIN&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- SELECT * FROM products WHERE attributes ? &apos;color&apos;;  -- CANNOT use this index&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Decision rule:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Querying by key existence (&lt;code&gt;? &apos;color&apos;&lt;/code&gt;) or multi-key containment → full GIN.&lt;/li&gt;
&lt;li&gt;Querying by specific key’s value with equality or range (&lt;code&gt;-&gt;&gt;&apos;price&apos; &gt; 100&lt;/code&gt;) → functional B-tree on that key.&lt;/li&gt;
&lt;li&gt;Only need containment (&lt;code&gt;@&gt;&lt;/code&gt;) and want a smaller index → &lt;code&gt;jsonb_path_ops&lt;/code&gt; GIN.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;when-not-to-create-an-index&quot;&gt;When NOT to Create an Index&lt;/h2&gt;
&lt;p&gt;Every index has a cost. Engineers tend to over-index because the benefit (faster reads) is visible immediately and the cost (slower writes, more storage, maintenance overhead) accumulates gradually.&lt;/p&gt;
&lt;h3 id=&quot;1-small-tables&quot;&gt;1. Small tables&lt;/h3&gt;
&lt;p&gt;PostgreSQL’s seq scan on a table that fits in a few pages is faster than consulting an index. The planner will ignore the index anyway. A “small table” threshold is roughly a few hundred rows, but this varies with row width. If &lt;code&gt;EXPLAIN&lt;/code&gt; shows &lt;code&gt;Seq Scan&lt;/code&gt; despite an index, the table might just be too small.&lt;/p&gt;
&lt;h3 id=&quot;2-write-heavy-tables-with-no-read-latency-requirement&quot;&gt;2. Write-heavy tables with no read latency requirement&lt;/h3&gt;
&lt;p&gt;Every &lt;code&gt;INSERT&lt;/code&gt; updates all indexes on the table. Every &lt;code&gt;UPDATE&lt;/code&gt; that changes an indexed column updates those indexes. Every &lt;code&gt;DELETE&lt;/code&gt; marks index entries as dead. On a table with 10 indexes receiving 50,000 inserts/sec, 10× the write I/O is going to index maintenance. If you never query some of those indexes directly, drop them.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Find indexes that are never used (since last stats reset)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; schemaname, tablename, indexname, idx_scan&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pg_stat_user_indexes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; idx_scan &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ORDER BY&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; schemaname, tablename;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An index with &lt;code&gt;idx_scan = 0&lt;/code&gt; since the last &lt;code&gt;pg_stat_reset()&lt;/code&gt; is a candidate for removal. Verify it’s not a constraint enforcement index (primary key, unique) before dropping.&lt;/p&gt;
&lt;h3 id=&quot;3-low-cardinality-columns-without-a-partial-index&quot;&gt;3. Low-cardinality columns (without a partial index)&lt;/h3&gt;
&lt;p&gt;A plain B-tree index on &lt;code&gt;is_deleted boolean&lt;/code&gt; or &lt;code&gt;status varchar&lt;/code&gt; with 3 values provides almost no filtering benefit. The planner will use a seq scan for any query that matches a non-trivial fraction of rows. Use a partial index instead.&lt;/p&gt;
&lt;h3 id=&quot;4-columns-that-are-only-queried-as-part-of-a-large-scan-anyway&quot;&gt;4. Columns that are only queried as part of a large scan anyway&lt;/h3&gt;
&lt;p&gt;If a column is always accessed with other conditions that already narrow the result to a small set, an index on it alone adds no value. The composite index with the narrowing column first is the right answer.&lt;/p&gt;
&lt;h3 id=&quot;5-during-bulk-loads&quot;&gt;5. During bulk loads&lt;/h3&gt;
&lt;p&gt;Drop non-constraint indexes before a bulk insert, then rebuild afterward:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Before bulk load&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;DROP&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; CONCURRENTLY idx_orders_user_id;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;DROP&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; CONCURRENTLY idx_orders_created_at;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Load data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;\&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;COPY&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;orders.csv&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; CSV HEADER;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- After bulk load — building from scratch is faster than incremental maintenance&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; CONCURRENTLY&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; idx_orders_user_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders (user_id);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; CONCURRENTLY&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; idx_orders_created_at &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders (created_at);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Building an index from scratch is 3-10x faster than maintaining it through incremental inserts because PostgreSQL can sort the data once and write the B-tree in one pass. Incremental maintenance requires a random insertion for each row.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;index-maintenance&quot;&gt;Index Maintenance&lt;/h2&gt;
&lt;h3 id=&quot;index-bloat&quot;&gt;Index Bloat&lt;/h3&gt;
&lt;p&gt;MVCC keeps multiple versions of every row Postgres has updated or deleted but not yet vacuumed. Older versions (called &lt;strong&gt;dead tuples&lt;/strong&gt;) take space until autovacuum reclaims them. See &lt;a href=&quot;/blog/acid-properties-and-isolation-levels/&quot;&gt;ACID and Isolation Levels&lt;/a&gt; for why MVCC exists in the first place.&lt;/p&gt;
&lt;p&gt;Dead tuples in the heap have corresponding dead entries in every index on the table. &lt;code&gt;VACUUM&lt;/code&gt; removes dead heap tuples and marks dead index entries as reusable, but it does not compact the index pages or return space to the OS. Over time, especially after bulk deletes or updates, indexes accumulate &lt;strong&gt;bloat&lt;/strong&gt; — pages that are mostly empty but still occupy disk space and memory.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Check index bloat (requires pgstattuple extension)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; EXTENSION &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;IF&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; NOT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; EXISTS&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pgstattuple;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pgstatindex(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;idx_orders_user_id&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- free_percent &gt; 20-30% is a sign of bloat worth addressing&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For severe bloat, rebuild the index:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Non-concurrent: fast but locks the table (avoid in production)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;REINDEX &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;INDEX&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; idx_orders_user_id;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Concurrent: safe in production, no table lock&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;REINDEX &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;INDEX&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; CONCURRENTLY idx_orders_user_id;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Or: create a new index, swap, drop old (manual concurrent reindex)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; CONCURRENTLY&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; idx_orders_user_id_new &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders (user_id);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;DROP&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; CONCURRENTLY idx_orders_user_id;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ALTER&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; idx_orders_user_id_new RENAME &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;TO&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; idx_orders_user_id;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;create-index-concurrently--adding-indexes-without-downtime&quot;&gt;&lt;code&gt;CREATE INDEX CONCURRENTLY&lt;/code&gt; — Adding Indexes Without Downtime&lt;/h3&gt;
&lt;p&gt;Always use &lt;code&gt;CONCURRENTLY&lt;/code&gt; in production when adding an index to a table that receives active queries:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Locks the table during build — ALL reads and writes block until done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_orders_user_id&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders (user_id);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Takes only brief locks — reads and writes continue the entire time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; CONCURRENTLY&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; idx_orders_user_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders (user_id);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On a table with millions of rows, a non-concurrent build can hold an &lt;code&gt;AccessExclusiveLock&lt;/code&gt; for minutes. Every query that touches the table queues behind it. In production, that’s a full outage for that table.&lt;/p&gt;
&lt;h4 id=&quot;what-concurrently-actually-does--three-phases&quot;&gt;What CONCURRENTLY Actually Does — Three Phases&lt;/h4&gt;
&lt;p&gt;The implementation is more subtle than “just build it without locking”:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 1 — Snapshot 1 + initial build:&lt;/strong&gt;
PostgreSQL takes a snapshot of the table and builds an index on all rows visible in that snapshot. It holds only a &lt;code&gt;ShareUpdateExclusiveLock&lt;/code&gt; during this phase — concurrent reads and writes are fully allowed. New writes that arrive during Phase 1 are not yet in the index.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 2 — Wait for old transactions:&lt;/strong&gt;
PostgreSQL waits until all transactions that started before Phase 1 ended have committed or rolled back. This is the safety gate. Any transaction still running from before the index build started might have a view of the table that doesn’t include the Phase 1 index. PostgreSQL must wait them out.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 3 — Snapshot 2 + catch-up:&lt;/strong&gt;
Takes a second snapshot, scans the heap again, and indexes any rows written between Phase 1 and Phase 2 that were missed. Takes another brief &lt;code&gt;ShareUpdateExclusiveLock&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After Phase 3, the index is fully consistent and the planner can use it.&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 942 881&quot;&gt;&lt;svg class=&quot;d2-685481928 d2-svg&quot; width=&quot;942&quot; height=&quot;881&quot; viewBox=&quot;-13 27 942 881&quot;&gt;&lt;rect x=&quot;-13.000000&quot; y=&quot;27.000000&quot; width=&quot;942.000000&quot; height=&quot;881.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-685481928 .text {
	font-family: &quot;d2-685481928-font-regular&quot;;
}
@font-face {
	font-family: d2-685481928-font-regular;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-685481928 .text-italic {
	font-family: &quot;d2-685481928-font-italic&quot;;
}
@font-face {
	font-family: d2-685481928-font-italic;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-685481928 .fill-N1{fill:#0A0F25;}
		.d2-685481928 .fill-N2{fill:#676C7E;}
		.d2-685481928 .fill-N3{fill:#9499AB;}
		.d2-685481928 .fill-N4{fill:#CFD2DD;}
		.d2-685481928 .fill-N5{fill:#DEE1EB;}
		.d2-685481928 .fill-N6{fill:#EEF1F8;}
		.d2-685481928 .fill-N7{fill:#FFFFFF;}
		.d2-685481928 .fill-B1{fill:#0D32B2;}
		.d2-685481928 .fill-B2{fill:#0D32B2;}
		.d2-685481928 .fill-B3{fill:#E3E9FD;}
		.d2-685481928 .fill-B4{fill:#E3E9FD;}
		.d2-685481928 .fill-B5{fill:#EDF0FD;}
		.d2-685481928 .fill-B6{fill:#F7F8FE;}
		.d2-685481928 .fill-AA2{fill:#4A6FF3;}
		.d2-685481928 .fill-AA4{fill:#EDF0FD;}
		.d2-685481928 .fill-AA5{fill:#F7F8FE;}
		.d2-685481928 .fill-AB4{fill:#EDF0FD;}
		.d2-685481928 .fill-AB5{fill:#F7F8FE;}
		.d2-685481928 .stroke-N1{stroke:#0A0F25;}
		.d2-685481928 .stroke-N2{stroke:#676C7E;}
		.d2-685481928 .stroke-N3{stroke:#9499AB;}
		.d2-685481928 .stroke-N4{stroke:#CFD2DD;}
		.d2-685481928 .stroke-N5{stroke:#DEE1EB;}
		.d2-685481928 .stroke-N6{stroke:#EEF1F8;}
		.d2-685481928 .stroke-N7{stroke:#FFFFFF;}
		.d2-685481928 .stroke-B1{stroke:#0D32B2;}
		.d2-685481928 .stroke-B2{stroke:#0D32B2;}
		.d2-685481928 .stroke-B3{stroke:#E3E9FD;}
		.d2-685481928 .stroke-B4{stroke:#E3E9FD;}
		.d2-685481928 .stroke-B5{stroke:#EDF0FD;}
		.d2-685481928 .stroke-B6{stroke:#F7F8FE;}
		.d2-685481928 .stroke-AA2{stroke:#4A6FF3;}
		.d2-685481928 .stroke-AA4{stroke:#EDF0FD;}
		.d2-685481928 .stroke-AA5{stroke:#F7F8FE;}
		.d2-685481928 .stroke-AB4{stroke:#EDF0FD;}
		.d2-685481928 .stroke-AB5{stroke:#F7F8FE;}
		.d2-685481928 .background-color-N1{background-color:#0A0F25;}
		.d2-685481928 .background-color-N2{background-color:#676C7E;}
		.d2-685481928 .background-color-N3{background-color:#9499AB;}
		.d2-685481928 .background-color-N4{background-color:#CFD2DD;}
		.d2-685481928 .background-color-N5{background-color:#DEE1EB;}
		.d2-685481928 .background-color-N6{background-color:#EEF1F8;}
		.d2-685481928 .background-color-N7{background-color:#FFFFFF;}
		.d2-685481928 .background-color-B1{background-color:#0D32B2;}
		.d2-685481928 .background-color-B2{background-color:#0D32B2;}
		.d2-685481928 .background-color-B3{background-color:#E3E9FD;}
		.d2-685481928 .background-color-B4{background-color:#E3E9FD;}
		.d2-685481928 .background-color-B5{background-color:#EDF0FD;}
		.d2-685481928 .background-color-B6{background-color:#F7F8FE;}
		.d2-685481928 .background-color-AA2{background-color:#4A6FF3;}
		.d2-685481928 .background-color-AA4{background-color:#EDF0FD;}
		.d2-685481928 .background-color-AA5{background-color:#F7F8FE;}
		.d2-685481928 .background-color-AB4{background-color:#EDF0FD;}
		.d2-685481928 .background-color-AB5{background-color:#F7F8FE;}
		.d2-685481928 .color-N1{color:#0A0F25;}
		.d2-685481928 .color-N2{color:#676C7E;}
		.d2-685481928 .color-N3{color:#9499AB;}
		.d2-685481928 .color-N4{color:#CFD2DD;}
		.d2-685481928 .color-N5{color:#DEE1EB;}
		.d2-685481928 .color-N6{color:#EEF1F8;}
		.d2-685481928 .color-N7{color:#FFFFFF;}
		.d2-685481928 .color-B1{color:#0D32B2;}
		.d2-685481928 .color-B2{color:#0D32B2;}
		.d2-685481928 .color-B3{color:#E3E9FD;}
		.d2-685481928 .color-B4{color:#E3E9FD;}
		.d2-685481928 .color-B5{color:#EDF0FD;}
		.d2-685481928 .color-B6{color:#F7F8FE;}
		.d2-685481928 .color-AA2{color:#4A6FF3;}
		.d2-685481928 .color-AA4{color:#EDF0FD;}
		.d2-685481928 .color-AA5{color:#F7F8FE;}
		.d2-685481928 .color-AB4{color:#EDF0FD;}
		.d2-685481928 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-685481928);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-685481928);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-685481928);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-685481928);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-685481928);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-685481928);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-685481928);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-685481928);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-685481928);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-685481928);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-685481928);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-685481928);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-685481928);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-685481928);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-685481928);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-685481928);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-685481928);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-685481928);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;Qw==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;12.000000&quot; y=&quot;52.000000&quot; width=&quot;138.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;81.000000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Client queries&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;UEc=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;282.000000&quot; y=&quot;52.000000&quot; width=&quot;123.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;343.500000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;PostgreSQL&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;SURY&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;702.000000&quot; y=&quot;52.000000&quot; width=&quot;114.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;759.000000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;New Index&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEMgLS0gKVswXQ==&quot;&gt;&lt;path d=&quot;M 81.000000 120.000000 L 81.000000 882.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-685481928)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KFBHIC0tIClbMF0=&quot;&gt;&lt;path d=&quot;M 343.500000 120.000000 L 343.500000 882.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-685481928)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KElEWCAtLSApWzBd&quot;&gt;&lt;path d=&quot;M 759.000000 120.000000 L 759.000000 882.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-685481928)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEMgLSZndDsgUEcpWzBd&quot;&gt;&lt;marker id=&quot;mk-d2-685481928-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 83.000000 198.000000 L 339.500000 198.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-685481928-3488378134)&quot; mask=&quot;url(#d2-685481928)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;212.500000&quot; y=&quot;204.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Writes continue normally&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFBHIC0mZ3Q7IElEWClbMF0=&quot;&gt;&lt;path d=&quot;M 345.500000 288.000000 L 755.000000 288.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-685481928-3488378134)&quot; mask=&quot;url(#d2-685481928)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;551.000000&quot; y=&quot;294.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Phase 1: scan heap snapshot 1, build index&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFBHIC0mZ3Q7IFBHKVswXQ==&quot;&gt;&lt;path d=&quot;M 345.500000 368.000000 L 476.000000 368.000000 S 486.000000 368.000000 486.000000 378.000000 L 486.000000 403.000000 S 486.000000 413.000000 476.000000 413.000000 L 347.500000 413.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-685481928-3488378134)&quot; mask=&quot;url(#d2-685481928)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;486.500000&quot; y=&quot;396.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;ShareUpdateExclusiveLock (no blocking)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFBHIC0mZ3Q7IFBHKVsxXQ==&quot;&gt;&lt;path d=&quot;M 345.500000 483.000000 L 472.000000 483.000000 S 482.000000 483.000000 482.000000 493.000000 L 482.000000 518.000000 S 482.000000 528.000000 472.000000 528.000000 L 347.500000 528.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-685481928-3488378134)&quot; mask=&quot;url(#d2-685481928)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;482.500000&quot; y=&quot;511.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Wait: all txns before Phase 1 must finish&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFBHIC0mZ3Q7IElEWClbMV0=&quot;&gt;&lt;path d=&quot;M 345.500000 608.000000 L 755.000000 608.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-685481928-3488378134)&quot; mask=&quot;url(#d2-685481928)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;551.000000&quot; y=&quot;614.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Phase 3: catch-up scan for rows written during Phase 1&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KElEWCAtJmd0OyBJRFgpWzBd&quot;&gt;&lt;path d=&quot;M 761.000000 688.000000 L 829.000000 688.000000 S 839.000000 688.000000 839.000000 698.000000 L 839.000000 723.000000 S 839.000000 733.000000 829.000000 733.000000 L 763.000000 733.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-685481928-3488378134)&quot; mask=&quot;url(#d2-685481928)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;839.500000&quot; y=&quot;716.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Index marked VALID&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEMgLSZndDsgUEcpWzFd&quot;&gt;&lt;path d=&quot;M 83.000000 813.000000 L 339.500000 813.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-685481928-3488378134)&quot; mask=&quot;url(#d2-685481928)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;212.000000&quot; y=&quot;819.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Queries now use the new index&lt;/text&gt;&lt;/g&gt;&lt;mask id=&quot;d2-685481928&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-13&quot; y=&quot;27&quot; width=&quot;942&quot; height=&quot;881&quot;&gt;
&lt;rect x=&quot;-13&quot; y=&quot;27&quot; width=&quot;942&quot; height=&quot;881&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;129.000000&quot; y=&quot;188.000000&quot; width=&quot;167&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;409.000000&quot; y=&quot;278.000000&quot; width=&quot;284&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;352.000000&quot; y=&quot;380.000000&quot; width=&quot;269&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;352.000000&quot; y=&quot;495.000000&quot; width=&quot;261&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;371.000000&quot; y=&quot;598.000000&quot; width=&quot;360&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;772.000000&quot; y=&quot;700.000000&quot; width=&quot;135&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;109.000000&quot; y=&quot;803.000000&quot; width=&quot;206&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;h4 id=&quot;why-it-can-fail--invalid-indexes&quot;&gt;Why It Can Fail — INVALID Indexes&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;CREATE INDEX CONCURRENTLY&lt;/code&gt; can fail and leave behind an &lt;code&gt;INVALID&lt;/code&gt; index in two situations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A long-running transaction never ends.&lt;/strong&gt; Phase 2 waits for old transactions to close. If a transaction started before Phase 1 and stays open for hours (e.g., a forgotten &lt;code&gt;BEGIN&lt;/code&gt; in a psql session, a hung application connection), the build stalls indefinitely. The build waits &lt;em&gt;indefinitely&lt;/em&gt; until you cancel it. There is no automatic timeout — set a &lt;code&gt;lock_timeout&lt;/code&gt; or &lt;code&gt;statement_timeout&lt;/code&gt; if you need bounded waits. If the build is cancelled or fails, the partially-built index is left in &lt;code&gt;INVALID&lt;/code&gt; state and must be &lt;code&gt;REINDEX&lt;/code&gt;-ed or &lt;code&gt;DROP&lt;/code&gt;-ed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A deadlock or unique constraint violation.&lt;/strong&gt; If the index is unique and a duplicate value is inserted during the build, the index is marked &lt;code&gt;INVALID&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;An &lt;code&gt;INVALID&lt;/code&gt; index is not used by the planner, but it does consume write overhead — every insert/update/delete still maintains it. You must drop and recreate it.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Find INVALID indexes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; schemaname, tablename, indexname&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pg_indexes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; indexname &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;IN&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; indexrelid::regclass::&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;text&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pg_index&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    WHERE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; NOT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; indisvalid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Drop the invalid index (also concurrent to avoid blocking)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;DROP&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; CONCURRENTLY idx_orders_user_id;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Recreate — make sure no long-running transactions are open first&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; CONCURRENTLY&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; idx_orders_user_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders (user_id);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;constraints-and-gotchas&quot;&gt;Constraints and Gotchas&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Cannot run inside a transaction block.&lt;/strong&gt; &lt;code&gt;CONCURRENTLY&lt;/code&gt; requires its own transaction management across the three phases:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;BEGIN&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; CONCURRENTLY&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; idx_orders_user_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders (user_id);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- ERROR: CREATE INDEX CONCURRENTLY cannot run inside a transaction block&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ROLLBACK&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Takes longer overall.&lt;/strong&gt; The concurrent build does more total work than a non-concurrent one (two heap scans, phase wait). On a large table it may take 2-3x as long wall-clock time, though your application doesn’t feel it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Unique indexes need extra care.&lt;/strong&gt; For &lt;code&gt;CREATE UNIQUE INDEX CONCURRENTLY&lt;/code&gt;, Phase 2 also checks for duplicates in the rows written during Phase 1. If duplicates exist, the index fails as &lt;code&gt;INVALID&lt;/code&gt; — it won’t silently ignore them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;REINDEX CONCURRENTLY&lt;/code&gt; for rebuilding existing indexes&lt;/strong&gt; (PostgreSQL 12+):&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Rebuild a bloated or corrupt index without locking&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;REINDEX &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;INDEX&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; CONCURRENTLY idx_orders_user_id;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Rebuild all indexes on a table concurrently&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;REINDEX &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;TABLE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; CONCURRENTLY orders;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Same three-phase mechanics, same INVALID-index risk on failure.&lt;/p&gt;
&lt;h4 id=&quot;pre-flight-checklist-before-a-large-concurrent-build&quot;&gt;Pre-flight Checklist Before a Large Concurrent Build&lt;/h4&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- 1. Check for long-running transactions that would stall Phase 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pid, &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; xact_start &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;AS&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; duration, &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, query&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pg_stat_activity&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; xact_start &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;IS NOT NULL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ORDER BY&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; duration &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;DESC&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Kill any that have been running for hours and are idle:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- SELECT pg_terminate_backend(pid);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- 2. Estimate index build time by checking table size&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pg_size_pretty(pg_total_relation_size(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;orders&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- 3. Monitor build progress (PostgreSQL 12+)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; phase, blocks_done, blocks_total,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;       round&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; blocks_done &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; nullif&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(blocks_total, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;AS&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pct&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pg_stat_progress_create_index&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; relid &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;orders&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;::regclass;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;pg_stat_progress_create_index&lt;/code&gt; view is invaluable for large tables — it shows exactly which phase the build is in and how far through the heap scan it is.&lt;/p&gt;
&lt;h3 id=&quot;autovacuum-and-index-health&quot;&gt;Autovacuum and Index Health&lt;/h3&gt;
&lt;p&gt;PostgreSQL’s autovacuum process runs automatically when a table accumulates enough dead tuples (controlled by &lt;code&gt;autovacuum_vacuum_threshold&lt;/code&gt; and &lt;code&gt;autovacuum_vacuum_scale_factor&lt;/code&gt;). It cleans up dead heap tuples and index entries. Without autovacuum:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Index entries accumulate as dead, causing index scans to become slower (more dead entries to skip).&lt;/li&gt;
&lt;li&gt;The visibility map becomes stale, preventing index-only scans.&lt;/li&gt;
&lt;li&gt;Table and index size grow unboundedly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For high-write tables, autovacuum may not keep up with the default settings. Tune it per table:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ALTER&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; TABLE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    autovacuum_vacuum_scale_factor &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;01&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,  &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- vacuum when 1% rows are dead (default 20%)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    autovacuum_vacuum_cost_delay &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;         -- less throttling for this table&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;bloom-filter-indexes&quot;&gt;Bloom Filter Indexes&lt;/h2&gt;
&lt;p&gt;PostgreSQL 9.6+ ships a &lt;code&gt;bloom&lt;/code&gt; index access method as a contrib extension. It’s a specialized index type built on the classic Bloom filter data structure — useful in a narrow but real scenario that no other index type handles well.&lt;/p&gt;
&lt;h3 id=&quot;what-a-bloom-filter-is&quot;&gt;What a Bloom Filter Is&lt;/h3&gt;
&lt;p&gt;A Bloom filter is a space-efficient probabilistic data structure that answers one question: &lt;strong&gt;“Has this value been seen before?”&lt;/strong&gt; It can answer definitively “no” (the value is definitely absent) but only probabilistically “yes” (the value &lt;em&gt;might&lt;/em&gt; be present — with a configurable false-positive rate).&lt;/p&gt;
&lt;p&gt;Internally it’s a bit array. To insert a value, hash it with &lt;code&gt;k&lt;/code&gt; different hash functions, and set those &lt;code&gt;k&lt;/code&gt; bits. To test membership, hash the query value the same way and check whether all &lt;code&gt;k&lt;/code&gt; bits are set. If any bit is unset, the value is definitely not in the set. If all are set, the value is &lt;em&gt;probably&lt;/em&gt; in the set — some bits may have been set by other values.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Value &quot;alice&quot; → hash functions → set bits [3, 17, 42, 89]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Value &quot;bob&quot;   → hash functions → set bits [7, 17, 55, 91]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Query &quot;alice&quot;: check bits [3, 17, 42, 89] — all set → probably present (fetch heap to confirm)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Query &quot;carol&quot;: check bits [2, 18, 43, 89] — bit 2 unset → definitely absent (skip heap entirely)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;postgresqls-bloom-index&quot;&gt;PostgreSQL’s Bloom Index&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; EXTENSION &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;IF&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; NOT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; EXISTS&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; bloom;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_orders_bloom&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;USING&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; bloom (user_id, &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, region)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WITH&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 80&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, col1 &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, col2 &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, col3 &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;length&lt;/code&gt; — size of the bloom signature per row in bits (8–4096, default 80)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;col1/col2/col3&lt;/code&gt; — number of hash functions per column (1–4096, default 2)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The index stores a fixed-length bit signature for each row. More bits and more hash functions = fewer false positives, larger index.&lt;/p&gt;
&lt;h3 id=&quot;the-one-scenario-where-bloom-beats-everything-else&quot;&gt;The One Scenario Where Bloom Beats Everything Else&lt;/h3&gt;
&lt;p&gt;A bloom index is specifically designed for tables where you need equality searches across &lt;strong&gt;many columns in arbitrary combinations&lt;/strong&gt; — not a fixed set of columns you always query together.&lt;/p&gt;
&lt;p&gt;Consider a user activity log table:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; TABLE&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; activity_log&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    id          &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;bigserial&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; PRIMARY KEY&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    user_id     &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    device_id   &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    session_id  &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    action_type &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    country_id  &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    partner_id  &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;int&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Queries come in any combination:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; user_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 42&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; country_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; device_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 99&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; action_type &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; partner_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 7&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; session_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 1234&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; country_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; user_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 42&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; device_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 99&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; partner_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 7&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To cover all possible combinations with B-tree composite indexes, you’d need potentially dozens of indexes — one for each common combination, with correct column ordering. That’s enormous write overhead and storage.&lt;/p&gt;
&lt;p&gt;With a single bloom index covering all six columns, any equality condition on any subset of those columns can use the one index:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_activity_bloom&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; activity_log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;USING&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; bloom (user_id, device_id, session_id, action_type, country_id, partner_id);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The index signature for each row is a bitwise OR of the per-column signatures. A query hashes its filter values, checks whether all resulting bits are set in a row’s signature. Rows that don’t match the bit pattern are skipped without ever reading the heap. Rows whose bit pattern might match are fetched and rechecked.&lt;/p&gt;
&lt;h3 id=&quot;the-trade-offs&quot;&gt;The Trade-offs&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;False positives are normal and expected.&lt;/strong&gt; A bloom index trades a small rate of unnecessary heap fetches for dramatically smaller index size and simpler maintenance. The planner knows this — it always applies a recheck after the bloom scan. You’ll see it in &lt;code&gt;EXPLAIN&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Bitmap Heap Scan on activity_log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Recheck Cond: ((user_id = 42) AND (country_id = 5))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Rows Removed by Index Recheck: 23      ← false positives fetched from heap&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  -&gt;  Bitmap Index Scan on idx_activity_bloom&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        Index Cond: ((user_id = 42) AND (country_id = 5))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Only supports equality (&lt;code&gt;=&lt;/code&gt;).&lt;/strong&gt; No range, no &lt;code&gt;LIKE&lt;/code&gt;, no &lt;code&gt;ORDER BY&lt;/code&gt;. Bloom is an existence check — it can’t reason about ordering or ranges.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Not useful for high-selectivity single-column queries.&lt;/strong&gt; A B-tree beats bloom for &lt;code&gt;WHERE user_id = 42&lt;/code&gt; alone. Bloom shines when the combination of multiple equality conditions provides selectivity that no single-column B-tree index can.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tuning the false-positive rate:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- More bits per row = fewer false positives, larger index&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Default (length=80): ~1-3% false positive rate for typical data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Higher length trades storage for fewer wasted heap fetches&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Measure current false-positive rate:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;EXPLAIN (ANALYZE, BUFFERS)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; activity_log &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; user_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 42&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; country_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Look at &quot;Rows Removed by Index Recheck&quot; vs total rows fetched&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- If removal rate &gt; 20-30%, increase length&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;when-to-reach-for-bloom&quot;&gt;When to Reach for Bloom&lt;/h3&gt;

































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Situation&lt;/th&gt;&lt;th&gt;Use Bloom?&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Many columns, all equality, arbitrary combinations&lt;/td&gt;&lt;td&gt;Yes — this is exactly what it’s for&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;High-cardinality single column&lt;/td&gt;&lt;td&gt;No — B-tree is better&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Range queries&lt;/td&gt;&lt;td&gt;No — bloom can’t help&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Fixed set of columns always queried together&lt;/td&gt;&lt;td&gt;No — composite B-tree is better&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Write-heavy table, need to minimize index count&lt;/td&gt;&lt;td&gt;Yes — one bloom index vs many B-trees&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Need to check “has this user_id + device_id ever appeared together?”&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;In practice, bloom indexes appear most in analytics tables, event logs, and data warehouse-style schemas where ad-hoc multi-column equality filtering is common and you want to avoid maintaining a combinatorial explosion of B-tree indexes.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;common-mistakes-checklist&quot;&gt;Common Mistakes Checklist&lt;/h2&gt;
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;UUIDv4 as a primary key on a high-write table.&lt;/strong&gt; Random insertion order causes constant B-tree page splits, hurts insert latency, and inflates the index well past what sequential keys would. Use UUIDv7 (time-prefixed) or &lt;code&gt;BIGSERIAL&lt;/code&gt;.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;&lt;code&gt;CREATE INDEX&lt;/code&gt; without &lt;code&gt;CONCURRENTLY&lt;/code&gt; in production.&lt;/strong&gt; Locks the table against writes for the duration of the build. Always use &lt;code&gt;CREATE INDEX CONCURRENTLY&lt;/code&gt; on a live system — and watch for invalid indexes if it fails partway through (&lt;code&gt;SELECT … FROM pg_index WHERE NOT indisvalid&lt;/code&gt;).&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Indexing a low-cardinality column on its own.&lt;/strong&gt; A boolean or 3-value status column has too few distinct values for B-tree to help. Use a partial index on the selective subset instead.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Wrapping the indexed column in a function.&lt;/strong&gt; &lt;code&gt;WHERE LOWER(email) = &apos;x&apos;&lt;/code&gt; won’t use an index on &lt;code&gt;email&lt;/code&gt; unless you have a functional index on &lt;code&gt;LOWER(email)&lt;/code&gt;. Same for &lt;code&gt;created_at::date&lt;/code&gt;, &lt;code&gt;EXTRACT(...)&lt;/code&gt;, type casts, and most function applications.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Composite index column order doesn’t match the query.&lt;/strong&gt; A &lt;code&gt;(a, b, c)&lt;/code&gt; composite is usable for &lt;code&gt;WHERE a = …&lt;/code&gt;, &lt;code&gt;WHERE a = … AND b = …&lt;/code&gt;, and &lt;code&gt;WHERE a = … AND b = … AND c = …&lt;/code&gt; — but not for &lt;code&gt;WHERE b = …&lt;/code&gt; alone. Lead with the highest-selectivity equality columns; trailing columns are only useful when the leading columns are constrained.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Mismatched types in the predicate.&lt;/strong&gt; &lt;code&gt;WHERE int_col = &apos;42&apos;&lt;/code&gt; may not use an &lt;code&gt;int_col&lt;/code&gt; index because the comparison forces a cast. Make sure literals match column types — or cast the literal, not the column.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Indexing every column “just in case.”&lt;/strong&gt; Each index adds write amplification, takes up space, and gives the planner more shapes to consider. Index what you query; remove indexes that &lt;code&gt;pg_stat_user_indexes&lt;/code&gt; shows &lt;code&gt;idx_scan = 0&lt;/code&gt;.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Forgetting &lt;code&gt;ANALYZE&lt;/code&gt; after a bulk load.&lt;/strong&gt; Stale statistics lead the planner to ignore newly-useful indexes. Always &lt;code&gt;ANALYZE&lt;/code&gt; after big inserts or &lt;code&gt;COPY&lt;/code&gt;s.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Partial index whose &lt;code&gt;WHERE&lt;/code&gt; doesn’t match the query.&lt;/strong&gt; The query’s predicate must be a logical superset of the partial index’s predicate. &lt;code&gt;WHERE active = true AND created &gt; now()&lt;/code&gt; won’t use a &lt;code&gt;WHERE active = true&lt;/code&gt; partial index unless the planner can prove the subset relationship.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;&lt;code&gt;SELECT *&lt;/code&gt; defeating index-only scans.&lt;/strong&gt; Index-only scans require &lt;em&gt;every&lt;/em&gt; returned column to be in the index. Listing the specific columns you need (or adding &lt;code&gt;INCLUDE&lt;/code&gt; to the index) lets the index-only path light up.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;BRIN on data with no correlation.&lt;/strong&gt; BRIN assumes physical row order roughly matches indexed-value order. On a table with random insertion order, BRIN can be worse than a sequential scan. Check &lt;code&gt;correlation&lt;/code&gt; in &lt;code&gt;pg_stats&lt;/code&gt; before reaching for BRIN.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;&lt;code&gt;REINDEX&lt;/code&gt; as a reflex.&lt;/strong&gt; Modern Postgres rarely needs manual reindexing. Use it for genuinely bloated indexes (&lt;code&gt;pg_stat_user_indexes&lt;/code&gt; + &lt;code&gt;pgstattuple&lt;/code&gt;), not as a general fix.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;related-reading&quot;&gt;Related reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/btrees-and-bplus-trees/&quot;&gt;B-Trees and B+ Trees&lt;/a&gt; — the data structure underlying most of these index types.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/db-storage-and-indexing/&quot;&gt;How Databases Actually Store and Find Your Data&lt;/a&gt; — pages, heap fetches, and clustered vs heap storage.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/postgres-explain/&quot;&gt;Reading PostgreSQL EXPLAIN Output&lt;/a&gt; — see these indexes show up in plan nodes.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/acid-properties-and-isolation-levels/&quot;&gt;ACID and Isolation Levels&lt;/a&gt; — &lt;code&gt;CREATE INDEX CONCURRENTLY&lt;/code&gt;’s phases are isolation-level work.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/postgres-partitioning/&quot;&gt;Postgres Partitioning: Strategies, Advantages, and Pitfalls&lt;/a&gt; — local indexes per partition, partition pruning, and &lt;code&gt;CREATE INDEX CONCURRENTLY&lt;/code&gt; per-partition.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;quick-reference&quot;&gt;Quick Reference&lt;/h2&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 1477 944&quot;&gt;&lt;svg class=&quot;d2-3906411175 d2-svg&quot; width=&quot;1477&quot; height=&quot;944&quot; viewBox=&quot;-25 -25 1477 944&quot;&gt;&lt;rect x=&quot;-25.000000&quot; y=&quot;-25.000000&quot; width=&quot;1477.000000&quot; height=&quot;944.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-3906411175 .text-bold {
	font-family: &quot;d2-3906411175-font-bold&quot;;
}
@font-face {
	font-family: d2-3906411175-font-bold;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-3906411175 .text-italic {
	font-family: &quot;d2-3906411175-font-italic&quot;;
}
@font-face {
	font-family: d2-3906411175-font-italic;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-3906411175 .fill-N1{fill:#0A0F25;}
		.d2-3906411175 .fill-N2{fill:#676C7E;}
		.d2-3906411175 .fill-N3{fill:#9499AB;}
		.d2-3906411175 .fill-N4{fill:#CFD2DD;}
		.d2-3906411175 .fill-N5{fill:#DEE1EB;}
		.d2-3906411175 .fill-N6{fill:#EEF1F8;}
		.d2-3906411175 .fill-N7{fill:#FFFFFF;}
		.d2-3906411175 .fill-B1{fill:#0D32B2;}
		.d2-3906411175 .fill-B2{fill:#0D32B2;}
		.d2-3906411175 .fill-B3{fill:#E3E9FD;}
		.d2-3906411175 .fill-B4{fill:#E3E9FD;}
		.d2-3906411175 .fill-B5{fill:#EDF0FD;}
		.d2-3906411175 .fill-B6{fill:#F7F8FE;}
		.d2-3906411175 .fill-AA2{fill:#4A6FF3;}
		.d2-3906411175 .fill-AA4{fill:#EDF0FD;}
		.d2-3906411175 .fill-AA5{fill:#F7F8FE;}
		.d2-3906411175 .fill-AB4{fill:#EDF0FD;}
		.d2-3906411175 .fill-AB5{fill:#F7F8FE;}
		.d2-3906411175 .stroke-N1{stroke:#0A0F25;}
		.d2-3906411175 .stroke-N2{stroke:#676C7E;}
		.d2-3906411175 .stroke-N3{stroke:#9499AB;}
		.d2-3906411175 .stroke-N4{stroke:#CFD2DD;}
		.d2-3906411175 .stroke-N5{stroke:#DEE1EB;}
		.d2-3906411175 .stroke-N6{stroke:#EEF1F8;}
		.d2-3906411175 .stroke-N7{stroke:#FFFFFF;}
		.d2-3906411175 .stroke-B1{stroke:#0D32B2;}
		.d2-3906411175 .stroke-B2{stroke:#0D32B2;}
		.d2-3906411175 .stroke-B3{stroke:#E3E9FD;}
		.d2-3906411175 .stroke-B4{stroke:#E3E9FD;}
		.d2-3906411175 .stroke-B5{stroke:#EDF0FD;}
		.d2-3906411175 .stroke-B6{stroke:#F7F8FE;}
		.d2-3906411175 .stroke-AA2{stroke:#4A6FF3;}
		.d2-3906411175 .stroke-AA4{stroke:#EDF0FD;}
		.d2-3906411175 .stroke-AA5{stroke:#F7F8FE;}
		.d2-3906411175 .stroke-AB4{stroke:#EDF0FD;}
		.d2-3906411175 .stroke-AB5{stroke:#F7F8FE;}
		.d2-3906411175 .background-color-N1{background-color:#0A0F25;}
		.d2-3906411175 .background-color-N2{background-color:#676C7E;}
		.d2-3906411175 .background-color-N3{background-color:#9499AB;}
		.d2-3906411175 .background-color-N4{background-color:#CFD2DD;}
		.d2-3906411175 .background-color-N5{background-color:#DEE1EB;}
		.d2-3906411175 .background-color-N6{background-color:#EEF1F8;}
		.d2-3906411175 .background-color-N7{background-color:#FFFFFF;}
		.d2-3906411175 .background-color-B1{background-color:#0D32B2;}
		.d2-3906411175 .background-color-B2{background-color:#0D32B2;}
		.d2-3906411175 .background-color-B3{background-color:#E3E9FD;}
		.d2-3906411175 .background-color-B4{background-color:#E3E9FD;}
		.d2-3906411175 .background-color-B5{background-color:#EDF0FD;}
		.d2-3906411175 .background-color-B6{background-color:#F7F8FE;}
		.d2-3906411175 .background-color-AA2{background-color:#4A6FF3;}
		.d2-3906411175 .background-color-AA4{background-color:#EDF0FD;}
		.d2-3906411175 .background-color-AA5{background-color:#F7F8FE;}
		.d2-3906411175 .background-color-AB4{background-color:#EDF0FD;}
		.d2-3906411175 .background-color-AB5{background-color:#F7F8FE;}
		.d2-3906411175 .color-N1{color:#0A0F25;}
		.d2-3906411175 .color-N2{color:#676C7E;}
		.d2-3906411175 .color-N3{color:#9499AB;}
		.d2-3906411175 .color-N4{color:#CFD2DD;}
		.d2-3906411175 .color-N5{color:#DEE1EB;}
		.d2-3906411175 .color-N6{color:#EEF1F8;}
		.d2-3906411175 .color-N7{color:#FFFFFF;}
		.d2-3906411175 .color-B1{color:#0D32B2;}
		.d2-3906411175 .color-B2{color:#0D32B2;}
		.d2-3906411175 .color-B3{color:#E3E9FD;}
		.d2-3906411175 .color-B4{color:#E3E9FD;}
		.d2-3906411175 .color-B5{color:#EDF0FD;}
		.d2-3906411175 .color-B6{color:#F7F8FE;}
		.d2-3906411175 .color-AA2{color:#4A6FF3;}
		.d2-3906411175 .color-AA4{color:#EDF0FD;}
		.d2-3906411175 .color-AA5{color:#F7F8FE;}
		.d2-3906411175 .color-AB4{color:#EDF0FD;}
		.d2-3906411175 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-3906411175);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-3906411175);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-3906411175);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-3906411175);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-3906411175);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-3906411175);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-3906411175);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-3906411175);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-3906411175);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-3906411175);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-3906411175);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-3906411175);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-3906411175);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-3906411175);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-3906411175);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-3906411175);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-3906411175);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-3906411175);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;UQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;644.000000&quot; y=&quot;0.000000&quot; width=&quot;186.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;737.000000&quot; y=&quot;38.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;What kind of query?&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;RQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;0.000000&quot; y=&quot;166.000000&quot; width=&quot;139.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;69.500000&quot; y=&quot;204.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;69.500000&quot; dy=&quot;0.000000&quot;&gt;Equality only&lt;/tspan&gt;&lt;tspan x=&quot;69.500000&quot; dy=&quot;18.500000&quot;&gt;= , IN&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Ug==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;199.000000&quot; y=&quot;166.000000&quot; width=&quot;212.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;305.000000&quot; y=&quot;204.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;305.000000&quot; dy=&quot;0.000000&quot;&gt;Range / order&lt;/tspan&gt;&lt;tspan x=&quot;305.000000&quot; dy=&quot;18.500000&quot;&gt;&amp;#x3C; &gt; BETWEEN ORDER BY&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;RlQ=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;684.000000&quot; y=&quot;166.000000&quot; width=&quot;106.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;737.000000&quot; y=&quot;204.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;737.000000&quot; dy=&quot;0.000000&quot;&gt;Full-text&lt;/tspan&gt;&lt;tspan x=&quot;737.000000&quot; dy=&quot;18.500000&quot;&gt;@@&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;QVI=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;850.000000&quot; y=&quot;166.000000&quot; width=&quot;146.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;923.000000&quot; y=&quot;204.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;923.000000&quot; dy=&quot;0.000000&quot;&gt;Array / JSONB&lt;/tspan&gt;&lt;tspan x=&quot;923.000000&quot; dy=&quot;18.500000&quot;&gt;@&gt; &amp;#x26;&amp;#x26; ?&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;R0VP&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;1056.000000&quot; y=&quot;166.000000&quot; width=&quot;151.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;1131.500000&quot; y=&quot;204.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;1131.500000&quot; dy=&quot;0.000000&quot;&gt;Geospatial&lt;/tspan&gt;&lt;tspan x=&quot;1131.500000&quot; dy=&quot;18.500000&quot;&gt;&amp;#x26;&amp;#x26; &amp;#x3C;-&gt; PostGIS&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Uk5H&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;1267.000000&quot; y=&quot;166.000000&quot; width=&quot;160.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;1347.000000&quot; y=&quot;204.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;1347.000000&quot; dy=&quot;0.000000&quot;&gt;Date/time range&lt;/tspan&gt;&lt;tspan x=&quot;1347.000000&quot; dy=&quot;18.500000&quot;&gt;overlap&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;UFJFRg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;471.000000&quot; y=&quot;166.000000&quot; width=&quot;122.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;532.000000&quot; y=&quot;204.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;532.000000&quot; dy=&quot;0.000000&quot;&gt;Text prefix&lt;/tspan&gt;&lt;tspan x=&quot;532.000000&quot; dy=&quot;18.500000&quot;&gt;LIKE &apos;x%&apos;&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;QlQx&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;17.000000&quot; y=&quot;356.000000&quot; width=&quot;106.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;70.000000&quot; y=&quot;394.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;70.000000&quot; dy=&quot;0.000000&quot;&gt;B-tree&lt;/tspan&gt;&lt;tspan x=&quot;70.000000&quot; dy=&quot;18.500000&quot;&gt;(default)&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;QlQy&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;261.000000&quot; y=&quot;364.000000&quot; width=&quot;88.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;305.000000&quot; y=&quot;402.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;B-tree&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;QlQz&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;445.000000&quot; y=&quot;348.000000&quot; width=&quot;174.000000&quot; height=&quot;98.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;532.000000&quot; y=&quot;386.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;532.000000&quot; dy=&quot;0.000000&quot;&gt;B-tree&lt;/tspan&gt;&lt;tspan x=&quot;532.000000&quot; dy=&quot;17.666667&quot;&gt;(text_pattern_ops&lt;/tspan&gt;&lt;tspan x=&quot;532.000000&quot; dy=&quot;17.666667&quot;&gt;if non-C locale)&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;R0lOMQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;679.000000&quot; y=&quot;356.000000&quot; width=&quot;115.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;736.500000&quot; y=&quot;394.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;736.500000&quot; dy=&quot;0.000000&quot;&gt;GIN&lt;/tspan&gt;&lt;tspan x=&quot;736.500000&quot; dy=&quot;18.500000&quot;&gt;(tsvector)&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;R0lOMg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;887.000000&quot; y=&quot;364.000000&quot; width=&quot;71.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;922.500000&quot; y=&quot;402.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;GIN&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;R0lTVDE=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;1075.000000&quot; y=&quot;356.000000&quot; width=&quot;112.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;1131.000000&quot; y=&quot;394.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;1131.000000&quot; dy=&quot;0.000000&quot;&gt;GiST&lt;/tspan&gt;&lt;tspan x=&quot;1131.000000&quot; dy=&quot;18.500000&quot;&gt;(PostGIS)&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;R0lTVDI=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;1308.000000&quot; y=&quot;364.000000&quot; width=&quot;78.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;1347.000000&quot; y=&quot;402.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;GiST&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;QlJJTl9R&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;path d=&quot;M 305 691 C 304 691 303 691 303 691 L 182 630 C 181 629 181 628 182 628 L 303 567 C 304 566 306 566 308 567 L 429 627 C 430 628 430 629 429 629 L 307 691 C 307 691 306 691 305 691 Z&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#CFD2DD&quot; class=&quot;stroke-B1 fill-N4&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;text x=&quot;305.000000&quot; y=&quot;626.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;305.000000&quot; dy=&quot;0.000000&quot;&gt;Table &gt; 1GB&lt;/tspan&gt;&lt;tspan x=&quot;305.000000&quot; dy=&quot;18.500000&quot;&gt;+ append-only?&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;QlJJTg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;210.000000&quot; y=&quot;812.000000&quot; width=&quot;190.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;305.000000&quot; y=&quot;850.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;305.000000&quot; dy=&quot;0.000000&quot;&gt;BRIN&lt;/tspan&gt;&lt;tspan x=&quot;305.000000&quot; dy=&quot;18.500000&quot;&gt;(+ check correlation)&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFEgLSZndDsgRSlbMF0=&quot;&gt;&lt;marker id=&quot;mk-d2-3906411175-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 641.515307 44.818970 C 184.298996 101.713997 69.500000 126.000000 69.500000 162.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3906411175-3488378134)&quot; mask=&quot;url(#d2-3906411175)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KFEgLSZndDsgUilbMF0=&quot;&gt;&lt;path d=&quot;M 641.536003 51.265780 C 372.700012 102.976997 305.000000 126.000000 305.000000 162.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3906411175-3488378134)&quot; mask=&quot;url(#d2-3906411175)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KFEgLSZndDsgRlQpWzBd&quot;&gt;&lt;path d=&quot;M 736.500000 68.000000 C 736.500000 106.000000 736.500000 126.000000 736.500000 162.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3906411175-3488378134)&quot; mask=&quot;url(#d2-3906411175)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KFEgLSZndDsgQVIpWzBd&quot;&gt;&lt;path d=&quot;M 812.326276 66.815302 C 900.099976 106.000000 922.500000 126.000000 922.500000 162.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3906411175-3488378134)&quot; mask=&quot;url(#d2-3906411175)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KFEgLSZndDsgR0VPKVswXQ==&quot;&gt;&lt;path d=&quot;M 832.456875 52.979087 C 1070.900024 103.313004 1131.000000 126.000000 1131.000000 162.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3906411175-3488378134)&quot; mask=&quot;url(#d2-3906411175)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KFEgLSZndDsgUk5HKVswXQ==&quot;&gt;&lt;path d=&quot;M 832.481670 45.924155 C 1243.300049 101.930000 1346.500000 126.000000 1346.500000 162.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3906411175-3488378134)&quot; mask=&quot;url(#d2-3906411175)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KFEgLSZndDsgUFJFRilbMF0=&quot;&gt;&lt;path d=&quot;M 653.147231 66.753158 C 556.599976 106.000000 532.000000 126.000000 532.000000 162.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3906411175-3488378134)&quot; mask=&quot;url(#d2-3906411175)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEUgLSZndDsgQlQxKVswXQ==&quot;&gt;&lt;path d=&quot;M 69.500000 250.000000 C 69.500000 288.000000 69.500000 309.600006 69.500000 352.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3906411175-3488378134)&quot; mask=&quot;url(#d2-3906411175)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KFIgLSZndDsgQlQyKVswXQ==&quot;&gt;&lt;path d=&quot;M 305.000000 250.000000 C 305.000000 288.000000 305.000000 311.200012 305.000000 360.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3906411175-3488378134)&quot; mask=&quot;url(#d2-3906411175)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEZUIC0mZ3Q7IEdJTjEpWzBd&quot;&gt;&lt;path d=&quot;M 736.500000 250.000000 C 736.500000 288.000000 736.500000 309.600006 736.500000 352.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3906411175-3488378134)&quot; mask=&quot;url(#d2-3906411175)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEFSIC0mZ3Q7IEdJTjIpWzBd&quot;&gt;&lt;path d=&quot;M 922.500000 250.000000 C 922.500000 288.000000 922.500000 311.200012 922.500000 360.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3906411175-3488378134)&quot; mask=&quot;url(#d2-3906411175)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEdFTyAtJmd0OyBHSVNUMSlbMF0=&quot;&gt;&lt;path d=&quot;M 1131.000000 250.000000 C 1131.000000 288.000000 1131.000000 309.600006 1131.000000 352.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3906411175-3488378134)&quot; mask=&quot;url(#d2-3906411175)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KFJORyAtJmd0OyBHSVNUMilbMF0=&quot;&gt;&lt;path d=&quot;M 1346.500000 250.000000 C 1346.500000 288.000000 1346.500000 311.200012 1346.500000 360.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3906411175-3488378134)&quot; mask=&quot;url(#d2-3906411175)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KFBSRUYgLSZndDsgQlQzKVswXQ==&quot;&gt;&lt;path d=&quot;M 532.000000 250.000000 C 532.000000 288.000000 532.000000 308.000000 532.000000 344.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3906411175-3488378134)&quot; mask=&quot;url(#d2-3906411175)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEJUMiAtJmd0OyBCUklOX1EpWzBd&quot;&gt;&lt;path d=&quot;M 299.142229 431.467740 C 288.299988 491.100006 287.600006 519.400024 295.357298 567.051971&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3906411175-3488378134)&quot; mask=&quot;url(#d2-3906411175)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEJSSU5fUSAtJmd0OyBCUklOKVswXQ==&quot;&gt;&lt;path d=&quot;M 305.000000 693.000000 C 305.000000 739.400024 305.000000 763.700012 305.000000 808.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3906411175-3488378134)&quot; mask=&quot;url(#d2-3906411175)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;305.000000&quot; y=&quot;757.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Yes&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEJSSU5fUSAtJmd0OyBCVDIpWzBd&quot;&gt;&lt;path d=&quot;M 314.326278 568.026794 C 322.399994 519.200012 321.700012 491.100006 311.215542 433.435480&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3906411175-3488378134)&quot; mask=&quot;url(#d2-3906411175)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;322.000000&quot; y=&quot;505.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;No&lt;/text&gt;&lt;/g&gt;&lt;mask id=&quot;d2-3906411175&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;1477&quot; height=&quot;944&quot;&gt;
&lt;rect x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;1477&quot; height=&quot;944&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;292.000000&quot; y=&quot;741.000000&quot; width=&quot;26&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;311.000000&quot; y=&quot;489.000000&quot; width=&quot;22&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;

























































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Situation&lt;/th&gt;&lt;th&gt;Recommendation&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;High-cardinality equality + range&lt;/td&gt;&lt;td&gt;B-tree&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Append-only 100GB+ table, time-range queries&lt;/td&gt;&lt;td&gt;BRIN (check correlation first)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Array or JSONB containment&lt;/td&gt;&lt;td&gt;GIN&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Full-text search&lt;/td&gt;&lt;td&gt;GIN on &lt;code&gt;tsvector&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Fuzzy / substring string matching&lt;/td&gt;&lt;td&gt;GIN + &lt;code&gt;pg_trgm&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Geospatial / range overlap&lt;/td&gt;&lt;td&gt;GiST&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;IP/CIDR subnet queries&lt;/td&gt;&lt;td&gt;SP-GiST&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;5% of rows are the hot “active” working set&lt;/td&gt;&lt;td&gt;Partial index on those rows&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;UUID primary key, high insert rate&lt;/td&gt;&lt;td&gt;Switch to UUIDv7 or BIGSERIAL&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;boolean&lt;/code&gt; or enum index&lt;/td&gt;&lt;td&gt;Partial index (avoid plain B-tree on low-cardinality column)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;LIKE &apos;%substring%&apos;&lt;/code&gt; or &lt;code&gt;ILIKE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;GIN + &lt;code&gt;pg_trgm&lt;/code&gt; extension&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;LIKE &apos;prefix%&apos;&lt;/code&gt; with non-C locale&lt;/td&gt;&lt;td&gt;B-tree with &lt;code&gt;text_pattern_ops&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;JSONB key value equality/range&lt;/td&gt;&lt;td&gt;Functional B-tree on &lt;code&gt;(col-&gt;&gt;&apos;key&apos;)&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Multi-condition AND with no composite index&lt;/td&gt;&lt;td&gt;BitmapAnd on individual indexes (but add composite if frequent)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Index not used despite existing&lt;/td&gt;&lt;td&gt;Check: function on column, type mismatch, low selectivity, stale stats, &lt;code&gt;random_page_cost&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Bulk insert&lt;/td&gt;&lt;td&gt;Drop non-constraint indexes, load, &lt;code&gt;CREATE INDEX CONCURRENTLY&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Many columns, equality-only, arbitrary combinations&lt;/td&gt;&lt;td&gt;Bloom filter index (&lt;code&gt;CREATE EXTENSION bloom&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Adding index to live production table&lt;/td&gt;&lt;td&gt;Always &lt;code&gt;CREATE INDEX CONCURRENTLY&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Rebuilding bloated/corrupt index in production&lt;/td&gt;&lt;td&gt;&lt;code&gt;REINDEX INDEX CONCURRENTLY&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Index build stalling (Phase 2 wait)&lt;/td&gt;&lt;td&gt;Check &lt;code&gt;pg_stat_activity&lt;/code&gt; for long-running transactions&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;</content:encoded></item><item><title>Go Profiling: From pprof to Flame Graphs</title><link>https://abhimanyunagurkar.com/blog/go-profiling/</link><guid isPermaLink="true">https://abhimanyunagurkar.com/blog/go-profiling/</guid><description>A practical guide to CPU, heap, goroutine, and trace profiling in Go — when to use each tool, how to wire it into a service, and how to read the output.</description><pubDate>Tue, 21 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Your service is slow. You have a theory — maybe it’s the database query, maybe it’s the JSON serialization, maybe it’s something else entirely. You could guess and change things one by one, deploying each time, hoping the graph gets better. Or you could profile it, look at exactly what your program is actually doing, and know for certain where the time or memory is going.&lt;/p&gt;
&lt;p&gt;Profiling is the practice of measuring a running program to find out where it spends resources. Go makes this exceptionally easy compared to most languages — the profiling tools are built into the standard library, the overhead is low enough to run in production, and the tooling is part of the Go CLI itself.&lt;/p&gt;
&lt;p&gt;This post is a deep guide. We’ll start from the very beginning — what profiling is, how it works under the hood — and work up through every profile type, how to collect them, how to read them, and how to turn what you see into a fix. If you’re a junior engineer who has never profiled anything before, this is written for you.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;why-guessing-doesnt-scale&quot;&gt;Why Guessing Doesn’t Scale&lt;/h2&gt;
&lt;p&gt;Before we get into the tooling, let’s talk about why profiling matters in the first place.&lt;/p&gt;
&lt;p&gt;When a program is slow, our instinct is to reason about it. “The database call is probably slow.” “We’re probably doing too much work per request.” These guesses are sometimes right. But they can also lead you down the wrong path — spending days optimizing code that wasn’t actually a bottleneck, while the real problem goes untouched.&lt;/p&gt;
&lt;p&gt;The deeper problem is that modern programs are complex. Your request handler calls a logger, which calls a string formatter, which calls an interface method, which calls a reflection-heavy library. Any of those could be the bottleneck. Your intuition, even after years of experience, will miss things that the profiler sees immediately.&lt;/p&gt;
&lt;p&gt;There’s a principle in performance work sometimes called &lt;strong&gt;Amdahl’s Law&lt;/strong&gt;: the speedup you get from optimizing a part of the program is limited by how much of the total time that part actually takes. If &lt;code&gt;json.Marshal&lt;/code&gt; is 5% of your request time and you make it 10× faster, your overall request time drops by only 4.5%. But if &lt;code&gt;json.Marshal&lt;/code&gt; is actually 60% of your request time, the same 10× improvement reduces total request time by 54%. Finding the part that actually dominates is everything.&lt;/p&gt;
&lt;p&gt;That’s what profiling gives you — the real numbers, not the guessed ones.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;how-go-works-background-you-need&quot;&gt;How Go Works: Background You Need&lt;/h2&gt;
&lt;p&gt;To read profiles intelligently, you need a mental model of what Go is doing at runtime. This isn’t deep theory — it’s the concepts you’ll see show up in every profile.&lt;/p&gt;
&lt;h3 id=&quot;goroutines-and-the-scheduler&quot;&gt;Goroutines and the Scheduler&lt;/h3&gt;
&lt;p&gt;Go is a concurrent language. Goroutines are lightweight execution threads managed by the Go runtime, not the operating system. You can have thousands or even millions of goroutines in a single process — each uses only a few kilobytes of stack memory (compared to megabytes for an OS thread).&lt;/p&gt;
&lt;p&gt;The Go scheduler is called the &lt;strong&gt;M:N scheduler&lt;/strong&gt; because it maps M goroutines onto N OS threads. The scheduler decides which goroutines run, when they run, and on which OS thread. This scheduling happens automatically, and most of the time you don’t need to think about it.&lt;/p&gt;
&lt;p&gt;But when you’re profiling, you do need to think about it, because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A goroutine that’s “doing work” shows up in a CPU profile&lt;/li&gt;
&lt;li&gt;A goroutine that’s “waiting” (on I/O, a channel, a mutex, a syscall) shows up in a goroutine or block profile&lt;/li&gt;
&lt;li&gt;The scheduler itself can become a bottleneck — this shows up in a trace&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The scheduler uses units called &lt;strong&gt;P (processor)&lt;/strong&gt; — you can think of a P as a slot that lets a goroutine actually run. By default, Go sets &lt;code&gt;GOMAXPROCS&lt;/code&gt; to the number of logical CPUs on the machine. If you have 8 CPUs, you have 8 Ps, meaning 8 goroutines can run simultaneously.&lt;/p&gt;
&lt;h3 id=&quot;the-garbage-collector&quot;&gt;The Garbage Collector&lt;/h3&gt;
&lt;p&gt;Go is a garbage-collected language. Memory that you allocate (with &lt;code&gt;make&lt;/code&gt;, &lt;code&gt;new&lt;/code&gt;, struct literals, slices, maps, interface values, closures, etc.) is managed by the runtime. The GC periodically scans live objects and frees memory that’s no longer reachable.&lt;/p&gt;
&lt;p&gt;This is convenient, but it has costs:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Allocation itself costs time.&lt;/strong&gt; Every &lt;code&gt;make([]byte, 1024)&lt;/code&gt; is work the runtime has to do.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GC cycles cost time.&lt;/strong&gt; When the GC runs, it uses CPU resources and can pause goroutines.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory pressure affects GC frequency.&lt;/strong&gt; If you allocate a lot, the GC runs more often.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The GC uses a &lt;strong&gt;stop-the-world (STW)&lt;/strong&gt; pause to do certain housekeeping tasks. In modern Go (1.14+), these pauses are extremely short — typically under 1 millisecond. But if you’re experiencing latency spikes at the 99th or 99.9th percentile, even a 1ms pause matters. The trace profiler is the tool that surfaces these.&lt;/p&gt;
&lt;p&gt;Understanding the GC is critical for reading memory profiles. When you see a function high in the heap profile, it’s because that function is responsible for keeping memory alive — either directly or through a chain of references.&lt;/p&gt;
&lt;h3 id=&quot;the-stack-vs-the-heap&quot;&gt;The Stack vs The Heap&lt;/h3&gt;
&lt;p&gt;In Go, every goroutine has its own &lt;strong&gt;stack&lt;/strong&gt; — a contiguous region of memory where local variables and function call frames live. The stack grows and shrinks automatically. This is fast because allocating on the stack is just a pointer increment.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;heap&lt;/strong&gt; is shared memory. When the compiler determines that a variable’s lifetime might extend beyond the function that creates it (through escape analysis), it allocates that variable on the heap instead. Heap allocations are slower and create work for the GC.&lt;/p&gt;
&lt;p&gt;You don’t control this directly — the compiler decides. But you can influence it, and this is one of the primary levers in memory optimization. When you see “allocations per operation” in a benchmark, it’s measuring how many times the compiler decided to use the heap.&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.6.9&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 686 533&quot;&gt;&lt;svg class=&quot;d2-773056503 d2-svg&quot; width=&quot;686&quot; height=&quot;533&quot; viewBox=&quot;17 -1 686 533&quot;&gt;&lt;rect x=&quot;17.000000&quot; y=&quot;-1.000000&quot; width=&quot;686.000000&quot; height=&quot;533.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-773056503 .text {
	font-family: &quot;d2-773056503-font-regular&quot;;
}
@font-face {
	font-family: d2-773056503-font-regular;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-773056503 .text-bold {
	font-family: &quot;d2-773056503-font-bold&quot;;
}
@font-face {
	font-family: d2-773056503-font-bold;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-773056503 .text-italic {
	font-family: &quot;d2-773056503-font-italic&quot;;
}
@font-face {
	font-family: d2-773056503-font-italic;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-773056503 .fill-N1{fill:#0A0F25;}
		.d2-773056503 .fill-N2{fill:#676C7E;}
		.d2-773056503 .fill-N3{fill:#9499AB;}
		.d2-773056503 .fill-N4{fill:#CFD2DD;}
		.d2-773056503 .fill-N5{fill:#DEE1EB;}
		.d2-773056503 .fill-N6{fill:#EEF1F8;}
		.d2-773056503 .fill-N7{fill:#FFFFFF;}
		.d2-773056503 .fill-B1{fill:#0D32B2;}
		.d2-773056503 .fill-B2{fill:#0D32B2;}
		.d2-773056503 .fill-B3{fill:#E3E9FD;}
		.d2-773056503 .fill-B4{fill:#E3E9FD;}
		.d2-773056503 .fill-B5{fill:#EDF0FD;}
		.d2-773056503 .fill-B6{fill:#F7F8FE;}
		.d2-773056503 .fill-AA2{fill:#4A6FF3;}
		.d2-773056503 .fill-AA4{fill:#EDF0FD;}
		.d2-773056503 .fill-AA5{fill:#F7F8FE;}
		.d2-773056503 .fill-AB4{fill:#EDF0FD;}
		.d2-773056503 .fill-AB5{fill:#F7F8FE;}
		.d2-773056503 .stroke-N1{stroke:#0A0F25;}
		.d2-773056503 .stroke-N2{stroke:#676C7E;}
		.d2-773056503 .stroke-N3{stroke:#9499AB;}
		.d2-773056503 .stroke-N4{stroke:#CFD2DD;}
		.d2-773056503 .stroke-N5{stroke:#DEE1EB;}
		.d2-773056503 .stroke-N6{stroke:#EEF1F8;}
		.d2-773056503 .stroke-N7{stroke:#FFFFFF;}
		.d2-773056503 .stroke-B1{stroke:#0D32B2;}
		.d2-773056503 .stroke-B2{stroke:#0D32B2;}
		.d2-773056503 .stroke-B3{stroke:#E3E9FD;}
		.d2-773056503 .stroke-B4{stroke:#E3E9FD;}
		.d2-773056503 .stroke-B5{stroke:#EDF0FD;}
		.d2-773056503 .stroke-B6{stroke:#F7F8FE;}
		.d2-773056503 .stroke-AA2{stroke:#4A6FF3;}
		.d2-773056503 .stroke-AA4{stroke:#EDF0FD;}
		.d2-773056503 .stroke-AA5{stroke:#F7F8FE;}
		.d2-773056503 .stroke-AB4{stroke:#EDF0FD;}
		.d2-773056503 .stroke-AB5{stroke:#F7F8FE;}
		.d2-773056503 .background-color-N1{background-color:#0A0F25;}
		.d2-773056503 .background-color-N2{background-color:#676C7E;}
		.d2-773056503 .background-color-N3{background-color:#9499AB;}
		.d2-773056503 .background-color-N4{background-color:#CFD2DD;}
		.d2-773056503 .background-color-N5{background-color:#DEE1EB;}
		.d2-773056503 .background-color-N6{background-color:#EEF1F8;}
		.d2-773056503 .background-color-N7{background-color:#FFFFFF;}
		.d2-773056503 .background-color-B1{background-color:#0D32B2;}
		.d2-773056503 .background-color-B2{background-color:#0D32B2;}
		.d2-773056503 .background-color-B3{background-color:#E3E9FD;}
		.d2-773056503 .background-color-B4{background-color:#E3E9FD;}
		.d2-773056503 .background-color-B5{background-color:#EDF0FD;}
		.d2-773056503 .background-color-B6{background-color:#F7F8FE;}
		.d2-773056503 .background-color-AA2{background-color:#4A6FF3;}
		.d2-773056503 .background-color-AA4{background-color:#EDF0FD;}
		.d2-773056503 .background-color-AA5{background-color:#F7F8FE;}
		.d2-773056503 .background-color-AB4{background-color:#EDF0FD;}
		.d2-773056503 .background-color-AB5{background-color:#F7F8FE;}
		.d2-773056503 .color-N1{color:#0A0F25;}
		.d2-773056503 .color-N2{color:#676C7E;}
		.d2-773056503 .color-N3{color:#9499AB;}
		.d2-773056503 .color-N4{color:#CFD2DD;}
		.d2-773056503 .color-N5{color:#DEE1EB;}
		.d2-773056503 .color-N6{color:#EEF1F8;}
		.d2-773056503 .color-N7{color:#FFFFFF;}
		.d2-773056503 .color-B1{color:#0D32B2;}
		.d2-773056503 .color-B2{color:#0D32B2;}
		.d2-773056503 .color-B3{color:#E3E9FD;}
		.d2-773056503 .color-B4{color:#E3E9FD;}
		.d2-773056503 .color-B5{color:#EDF0FD;}
		.d2-773056503 .color-B6{color:#F7F8FE;}
		.d2-773056503 .color-AA2{color:#4A6FF3;}
		.d2-773056503 .color-AA4{color:#EDF0FD;}
		.d2-773056503 .color-AA5{color:#F7F8FE;}
		.d2-773056503 .color-AB4{color:#EDF0FD;}
		.d2-773056503 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-773056503);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-773056503);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-773056503);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-773056503);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-773056503);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-773056503);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-773056503);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-773056503);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-773056503);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-773056503);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-773056503);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-773056503);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-773056503);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-773056503);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-773056503);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-773056503);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-773056503);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-773056503);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;Z29yb3V0aW5l&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;42.000000&quot; y=&quot;333.000000&quot; width=&quot;179.000000&quot; height=&quot;174.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#E3E9FD&quot; class=&quot;stroke-B1 fill-B4&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;131.500000&quot; y=&quot;320.000000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:28px&quot;&gt;Goroutine&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;cnVudGltZQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;46.000000&quot; y=&quot;64.000000&quot; width=&quot;632.000000&quot; height=&quot;183.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#E3E9FD&quot; class=&quot;stroke-B1 fill-B4&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;362.000000&quot; y=&quot;51.000000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:28px&quot;&gt;Runtime&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Z29yb3V0aW5lLlM=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;72.000000&quot; y=&quot;363.000000&quot; width=&quot;119.000000&quot; height=&quot;114.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;131.500000&quot; y=&quot;401.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;131.500000&quot; dy=&quot;0.000000&quot;&gt;Stack&lt;/tspan&gt;&lt;tspan x=&quot;131.500000&quot; dy=&quot;17.250000&quot;&gt;local vars&lt;/tspan&gt;&lt;tspan x=&quot;131.500000&quot; dy=&quot;17.250000&quot;&gt;fast alloc&lt;/tspan&gt;&lt;tspan x=&quot;131.500000&quot; dy=&quot;17.250000&quot;&gt;auto freed&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;cnVudGltZS5I&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;511.000000&quot; y=&quot;103.000000&quot; width=&quot;137.000000&quot; height=&quot;114.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;579.500000&quot; y=&quot;141.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;579.500000&quot; dy=&quot;0.000000&quot;&gt;Heap&lt;/tspan&gt;&lt;tspan x=&quot;579.500000&quot; dy=&quot;17.250000&quot;&gt;escaped vars&lt;/tspan&gt;&lt;tspan x=&quot;579.500000&quot; dy=&quot;17.250000&quot;&gt;slower alloc&lt;/tspan&gt;&lt;tspan x=&quot;579.500000&quot; dy=&quot;17.250000&quot;&gt;GC managed&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;cnVudGltZS5HQw==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;76.000000&quot; y=&quot;94.000000&quot; width=&quot;111.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;131.500000&quot; y=&quot;132.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;131.500000&quot; dy=&quot;0.000000&quot;&gt;Garbage&lt;/tspan&gt;&lt;tspan x=&quot;131.500000&quot; dy=&quot;18.500000&quot;&gt;Collector&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;cnVudGltZS4oR0MgLSZndDsgSClbMF0=&quot;&gt;&lt;marker id=&quot;mk-d2-773056503-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 189.000000 135.000000 C 247.800003 135.000000 411.799988 138.199997 507.032889 150.488115&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-773056503-3488378134)&quot; mask=&quot;url(#d2-773056503)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;349.500000&quot; y=&quot;142.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;scans and frees&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KGdvcm91dGluZS5TIC0mZ3Q7IHJ1bnRpbWUuSClbMF0=&quot;&gt;&lt;path d=&quot;M 193.000000 419.500000 C 248.600006 419.500000 411.799988 184.949997 507.046145 170.355832&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-773056503-3488378134)&quot; mask=&quot;url(#d2-773056503)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;342.000000&quot; y=&quot;282.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;342.000000&quot; dy=&quot;0.000000&quot;&gt;escape analysis&lt;/tspan&gt;&lt;tspan x=&quot;342.000000&quot; dy=&quot;18.500000&quot;&gt;decides&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;mask id=&quot;d2-773056503&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;17&quot; y=&quot;-1&quot; width=&quot;686&quot; height=&quot;533&quot;&gt;
&lt;rect x=&quot;17&quot; y=&quot;-1&quot; width=&quot;686&quot; height=&quot;533&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;73.000000&quot; y=&quot;292.000000&quot; width=&quot;117&quot; height=&quot;36&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;313.000000&quot; y=&quot;23.000000&quot; width=&quot;98&quot; height=&quot;36&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;94.500000&quot; y=&quot;385.500000&quot; width=&quot;74&quot; height=&quot;69&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;533.500000&quot; y=&quot;125.500000&quot; width=&quot;92&quot; height=&quot;69&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;98.500000&quot; y=&quot;116.500000&quot; width=&quot;66&quot; height=&quot;37&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;298.000000&quot; y=&quot;126.000000&quot; width=&quot;103&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;290.000000&quot; y=&quot;266.000000&quot; width=&quot;104&quot; height=&quot;37&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;hr&gt;
&lt;h2 id=&quot;how-profiling-actually-works&quot;&gt;How Profiling Actually Works&lt;/h2&gt;
&lt;p&gt;Before you use a profiler, it helps to understand what it’s doing. Go’s CPU profiler is a &lt;strong&gt;sampling profiler&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Here’s the idea: profiling every single instruction a program executes would slow it down enormously and produce too much data to be useful. Instead, a sampling profiler sets up a timer that fires at a regular interval — by default, 100 times per second (every 10 milliseconds). Each time the timer fires, the profiler records the current call stack of every running goroutine. After you collect thousands of these samples, you have a statistical picture of where the program spends its time.&lt;/p&gt;
&lt;p&gt;The functions that appear most often in the samples are the ones consuming the most CPU time. Functions that are called rarely or execute quickly appear infrequently.&lt;/p&gt;
&lt;p&gt;This means a few important things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CPU profiles are statistical, not exact.&lt;/strong&gt; A function that shows 42.86% of samples took roughly 42.86% of CPU time — it’s an approximation, not a precise measurement.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Very fast functions may be invisible.&lt;/strong&gt; If a function completes in under 10ms, it might never be sampled. This is why microbenchmarks (which run functions millions of times) are better for measuring tiny functions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The overhead is low because we’re only sampling.&lt;/strong&gt; At 100 samples/second, the profiler adds roughly 1-5% overhead, which is safe for production.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Memory (heap) profiling works differently — it instruments allocation calls directly, and the runtime samples allocations on average once per 512 KB allocated (probabilistic, not deterministic per-512KB; configurable with &lt;code&gt;runtime.MemProfileRate&lt;/code&gt;). Any allocation can trigger a sample; it is not a size filter.&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.6.9&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 1046 791&quot;&gt;&lt;svg class=&quot;d2-675025801 d2-svg&quot; width=&quot;1046&quot; height=&quot;791&quot; viewBox=&quot;-13 27 1046 791&quot;&gt;&lt;rect x=&quot;-13.000000&quot; y=&quot;27.000000&quot; width=&quot;1046.000000&quot; height=&quot;791.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-675025801 .text {
	font-family: &quot;d2-675025801-font-regular&quot;;
}
@font-face {
	font-family: d2-675025801-font-regular;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-675025801 .text-italic {
	font-family: &quot;d2-675025801-font-italic&quot;;
}
@font-face {
	font-family: d2-675025801-font-italic;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-675025801 .fill-N1{fill:#0A0F25;}
		.d2-675025801 .fill-N2{fill:#676C7E;}
		.d2-675025801 .fill-N3{fill:#9499AB;}
		.d2-675025801 .fill-N4{fill:#CFD2DD;}
		.d2-675025801 .fill-N5{fill:#DEE1EB;}
		.d2-675025801 .fill-N6{fill:#EEF1F8;}
		.d2-675025801 .fill-N7{fill:#FFFFFF;}
		.d2-675025801 .fill-B1{fill:#0D32B2;}
		.d2-675025801 .fill-B2{fill:#0D32B2;}
		.d2-675025801 .fill-B3{fill:#E3E9FD;}
		.d2-675025801 .fill-B4{fill:#E3E9FD;}
		.d2-675025801 .fill-B5{fill:#EDF0FD;}
		.d2-675025801 .fill-B6{fill:#F7F8FE;}
		.d2-675025801 .fill-AA2{fill:#4A6FF3;}
		.d2-675025801 .fill-AA4{fill:#EDF0FD;}
		.d2-675025801 .fill-AA5{fill:#F7F8FE;}
		.d2-675025801 .fill-AB4{fill:#EDF0FD;}
		.d2-675025801 .fill-AB5{fill:#F7F8FE;}
		.d2-675025801 .stroke-N1{stroke:#0A0F25;}
		.d2-675025801 .stroke-N2{stroke:#676C7E;}
		.d2-675025801 .stroke-N3{stroke:#9499AB;}
		.d2-675025801 .stroke-N4{stroke:#CFD2DD;}
		.d2-675025801 .stroke-N5{stroke:#DEE1EB;}
		.d2-675025801 .stroke-N6{stroke:#EEF1F8;}
		.d2-675025801 .stroke-N7{stroke:#FFFFFF;}
		.d2-675025801 .stroke-B1{stroke:#0D32B2;}
		.d2-675025801 .stroke-B2{stroke:#0D32B2;}
		.d2-675025801 .stroke-B3{stroke:#E3E9FD;}
		.d2-675025801 .stroke-B4{stroke:#E3E9FD;}
		.d2-675025801 .stroke-B5{stroke:#EDF0FD;}
		.d2-675025801 .stroke-B6{stroke:#F7F8FE;}
		.d2-675025801 .stroke-AA2{stroke:#4A6FF3;}
		.d2-675025801 .stroke-AA4{stroke:#EDF0FD;}
		.d2-675025801 .stroke-AA5{stroke:#F7F8FE;}
		.d2-675025801 .stroke-AB4{stroke:#EDF0FD;}
		.d2-675025801 .stroke-AB5{stroke:#F7F8FE;}
		.d2-675025801 .background-color-N1{background-color:#0A0F25;}
		.d2-675025801 .background-color-N2{background-color:#676C7E;}
		.d2-675025801 .background-color-N3{background-color:#9499AB;}
		.d2-675025801 .background-color-N4{background-color:#CFD2DD;}
		.d2-675025801 .background-color-N5{background-color:#DEE1EB;}
		.d2-675025801 .background-color-N6{background-color:#EEF1F8;}
		.d2-675025801 .background-color-N7{background-color:#FFFFFF;}
		.d2-675025801 .background-color-B1{background-color:#0D32B2;}
		.d2-675025801 .background-color-B2{background-color:#0D32B2;}
		.d2-675025801 .background-color-B3{background-color:#E3E9FD;}
		.d2-675025801 .background-color-B4{background-color:#E3E9FD;}
		.d2-675025801 .background-color-B5{background-color:#EDF0FD;}
		.d2-675025801 .background-color-B6{background-color:#F7F8FE;}
		.d2-675025801 .background-color-AA2{background-color:#4A6FF3;}
		.d2-675025801 .background-color-AA4{background-color:#EDF0FD;}
		.d2-675025801 .background-color-AA5{background-color:#F7F8FE;}
		.d2-675025801 .background-color-AB4{background-color:#EDF0FD;}
		.d2-675025801 .background-color-AB5{background-color:#F7F8FE;}
		.d2-675025801 .color-N1{color:#0A0F25;}
		.d2-675025801 .color-N2{color:#676C7E;}
		.d2-675025801 .color-N3{color:#9499AB;}
		.d2-675025801 .color-N4{color:#CFD2DD;}
		.d2-675025801 .color-N5{color:#DEE1EB;}
		.d2-675025801 .color-N6{color:#EEF1F8;}
		.d2-675025801 .color-N7{color:#FFFFFF;}
		.d2-675025801 .color-B1{color:#0D32B2;}
		.d2-675025801 .color-B2{color:#0D32B2;}
		.d2-675025801 .color-B3{color:#E3E9FD;}
		.d2-675025801 .color-B4{color:#E3E9FD;}
		.d2-675025801 .color-B5{color:#EDF0FD;}
		.d2-675025801 .color-B6{color:#F7F8FE;}
		.d2-675025801 .color-AA2{color:#4A6FF3;}
		.d2-675025801 .color-AA4{color:#EDF0FD;}
		.d2-675025801 .color-AA5{color:#F7F8FE;}
		.d2-675025801 .color-AB4{color:#EDF0FD;}
		.d2-675025801 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-675025801);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-675025801);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-675025801);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-675025801);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-675025801);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-675025801);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-675025801);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-675025801);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-675025801);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-675025801);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-675025801);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-675025801);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-675025801);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-675025801);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-675025801);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-675025801);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-675025801);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-675025801);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;VGltZXI=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;12.000000&quot; y=&quot;52.000000&quot; width=&quot;160.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;92.000000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;OS Timer (100Hz)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;UnVudGltZQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;231.000000&quot; y=&quot;52.000000&quot; width=&quot;124.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;293.000000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Go Runtime&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;UHJvZmlsZQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;668.000000&quot; y=&quot;52.000000&quot; width=&quot;133.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;734.500000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Profile Buffer&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;RmlsZQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;908.000000&quot; y=&quot;52.000000&quot; width=&quot;100.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;958.000000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;.out File&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFRpbWVyIC0tIClbMF0=&quot;&gt;&lt;path d=&quot;M 92.000000 120.000000 L 92.000000 792.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-675025801)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KFJ1bnRpbWUgLS0gKVswXQ==&quot;&gt;&lt;path d=&quot;M 293.000000 120.000000 L 293.000000 792.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-675025801)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KFByb2ZpbGUgLS0gKVswXQ==&quot;&gt;&lt;path d=&quot;M 734.500000 120.000000 L 734.500000 792.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-675025801)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEZpbGUgLS0gKVswXQ==&quot;&gt;&lt;path d=&quot;M 958.000000 120.000000 L 958.000000 792.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-675025801)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KFRpbWVyIC0mZ3Q7IFJ1bnRpbWUpWzBd&quot;&gt;&lt;marker id=&quot;mk-d2-675025801-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 94.000000 198.000000 L 289.000000 198.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-675025801-3488378134)&quot; mask=&quot;url(#d2-675025801)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;193.000000&quot; y=&quot;204.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;signal (every 10ms)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFJ1bnRpbWUgLSZndDsgUnVudGltZSlbMF0=&quot;&gt;&lt;path d=&quot;M 295.000000 278.000000 L 503.500000 278.000000 S 513.500000 278.000000 513.500000 288.000000 L 513.500000 313.000000 S 513.500000 323.000000 503.500000 323.000000 L 297.000000 323.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-675025801-3488378134)&quot; mask=&quot;url(#d2-675025801)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;513.500000&quot; y=&quot;306.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;signal each thread, capture stack of currently-running goroutine&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFJ1bnRpbWUgLSZndDsgUHJvZmlsZSlbMF0=&quot;&gt;&lt;path d=&quot;M 295.000000 403.000000 L 730.500000 403.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-675025801-3488378134)&quot; mask=&quot;url(#d2-675025801)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;513.500000&quot; y=&quot;409.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;record current call stack&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFJ1bnRpbWUgLSZndDsgUnVudGltZSlbMV0=&quot;&gt;&lt;path d=&quot;M 295.000000 483.000000 L 363.000000 483.000000 S 373.000000 483.000000 373.000000 493.000000 L 373.000000 518.000000 S 373.000000 528.000000 363.000000 528.000000 L 297.000000 528.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-675025801-3488378134)&quot; mask=&quot;url(#d2-675025801)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;373.500000&quot; y=&quot;511.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;resume goroutines&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFRpbWVyIC0mZ3Q7IFRpbWVyKVswXQ==&quot;&gt;&lt;path d=&quot;M 94.000000 598.000000 L 182.500000 598.000000 S 192.500000 598.000000 192.500000 608.000000 L 192.500000 633.000000 S 192.500000 643.000000 182.500000 643.000000 L 96.000000 643.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-675025801-3488378134)&quot; mask=&quot;url(#d2-675025801)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;192.500000&quot; y=&quot;626.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;repeat thousands of times...&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFByb2ZpbGUgLSZndDsgRmlsZSlbMF0=&quot;&gt;&lt;path d=&quot;M 736.500000 723.000000 L 954.000000 723.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-675025801-3488378134)&quot; mask=&quot;url(#d2-675025801)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;846.000000&quot; y=&quot;729.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;flush on StopCPUProfile()&lt;/text&gt;&lt;/g&gt;&lt;mask id=&quot;d2-675025801&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-13&quot; y=&quot;27&quot; width=&quot;1046&quot; height=&quot;791&quot;&gt;
&lt;rect x=&quot;-13&quot; y=&quot;27&quot; width=&quot;1046&quot; height=&quot;791&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;34.500000&quot; y=&quot;74.500000&quot; width=&quot;115&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;253.500000&quot; y=&quot;74.500000&quot; width=&quot;79&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;690.500000&quot; y=&quot;74.500000&quot; width=&quot;88&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;931.500000&quot; y=&quot;74.500000&quot; width=&quot;53&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;130.000000&quot; y=&quot;188.000000&quot; width=&quot;126&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;303.000000&quot; y=&quot;290.000000&quot; width=&quot;421&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;434.000000&quot; y=&quot;393.000000&quot; width=&quot;159&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;312.000000&quot; y=&quot;495.000000&quot; width=&quot;123&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;102.000000&quot; y=&quot;610.000000&quot; width=&quot;181&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;764.000000&quot; y=&quot;713.000000&quot; width=&quot;164&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-profile-types--what-each-one-tells-you&quot;&gt;The Profile Types — What Each One Tells You&lt;/h2&gt;
&lt;p&gt;Go provides seven distinct profile types. Each answers a different question about what your program is doing.&lt;/p&gt;
&lt;h3 id=&quot;cpu-profile&quot;&gt;CPU Profile&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;What it measures:&lt;/strong&gt; Where goroutines spend time when they are actively running — executing code, not waiting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How to think about it:&lt;/strong&gt; If you imagine all the time your program spends on the CPU sliced into 10ms intervals, the CPU profile shows you which function was at the top of the call stack during each of those slices. Functions that appear in many slices are consuming significant CPU.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it won’t tell you:&lt;/strong&gt; Time spent waiting. If your request handler takes 500ms but 450ms of that is waiting for a database response, the CPU profile might show only 50ms of actual work spread across various functions. The other 450ms doesn’t appear in the CPU profile because the goroutine was sleeping — not running.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Service is slow AND CPU usage is high (close to 100% on one or more cores)&lt;/li&gt;
&lt;li&gt;You want to optimize a tight computation&lt;/li&gt;
&lt;li&gt;You suspect inefficient algorithms or too much work per request&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;heap-profile&quot;&gt;Heap Profile&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;What it measures:&lt;/strong&gt; Memory currently allocated on the heap — specifically, which functions are responsible for keeping that memory alive at the time you take the snapshot.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Two views:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-inuse_space&lt;/code&gt;: how much memory is live right now (not yet freed by GC)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-inuse_objects&lt;/code&gt;: how many objects are live right now&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-alloc_space&lt;/code&gt;: total bytes allocated since the program started (even if later freed)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-alloc_objects&lt;/code&gt;: total number of allocations since the program started&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;How to think about it:&lt;/strong&gt; &lt;code&gt;-inuse_space&lt;/code&gt; tells you what’s holding memory right now — useful for debugging high memory usage. &lt;code&gt;-alloc_space&lt;/code&gt; tells you what’s been allocating over time — useful for finding GC pressure even when total memory isn’t that high.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Service is using more memory than expected&lt;/li&gt;
&lt;li&gt;Memory grows over time and doesn’t come down (potential leak)&lt;/li&gt;
&lt;li&gt;GC is running frequently and you want to reduce allocations&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;allocs-profile&quot;&gt;Allocs Profile&lt;/h3&gt;
&lt;p&gt;The Allocs profile is similar to the Heap profile but defaults to showing allocation counts rather than sizes. It records where allocations happened regardless of whether they’re still live. This is the right profile when you’re investigating GC pressure — you want to know what’s causing frequent GC cycles, not just what’s using memory right now.&lt;/p&gt;
&lt;h3 id=&quot;goroutine-profile&quot;&gt;Goroutine Profile&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;What it measures:&lt;/strong&gt; A snapshot of every goroutine that currently exists, and exactly where each one is paused — its full call stack.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How to think about it:&lt;/strong&gt; Imagine freezing your program at an instant in time and inspecting every thread of execution. You can see which goroutines are doing useful work, which are waiting on I/O, which are blocked on a channel, and which are stuck waiting for a lock.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Goroutine count is unexpectedly high and growing (goroutine leak)&lt;/li&gt;
&lt;li&gt;Suspected deadlock — the goroutine dump will show them all waiting on each other&lt;/li&gt;
&lt;li&gt;Requests seem to hang — you can see exactly where the goroutines handling those requests are blocked&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;mutex-profile&quot;&gt;Mutex Profile&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;What it measures:&lt;/strong&gt; Where goroutines are spending time waiting to acquire a mutex (lock). This is distinct from the goroutine profile because it focuses specifically on contention time — the cumulative time goroutines spent blocked on &lt;code&gt;sync.Mutex&lt;/code&gt; or &lt;code&gt;sync.RWMutex&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How to think about it:&lt;/strong&gt; Multiple goroutines competing for the same lock is serialization — it forces concurrency into a single-threaded bottleneck. The mutex profile shows you which locks are the most contested.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Requires opt-in:&lt;/strong&gt; Must call &lt;code&gt;runtime.SetMutexProfileFraction(n)&lt;/code&gt; to enable. Off by default.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Service does not scale when you add more CPUs&lt;/li&gt;
&lt;li&gt;CPU usage looks low but throughput isn’t improving with more goroutines&lt;/li&gt;
&lt;li&gt;You suspect lock contention under load&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;block-profile&quot;&gt;Block Profile&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;What it measures:&lt;/strong&gt; Where goroutines block on synchronization primitives: channel sends/receives, &lt;code&gt;select&lt;/code&gt;, &lt;code&gt;sync.Mutex&lt;/code&gt;, &lt;code&gt;sync.RWMutex&lt;/code&gt;, &lt;code&gt;sync.WaitGroup&lt;/code&gt;, &lt;code&gt;sync.Cond&lt;/code&gt;. It records the time goroutines spent waiting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How to think about it:&lt;/strong&gt; While the CPU profile shows busy time, the block profile shows waiting time. If your service is slow but CPU is idle, something is blocking goroutines. The block profile shows you what.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The key distinction from Mutex:&lt;/strong&gt; Block includes all synchronization, not just mutexes. Channel operations, &lt;code&gt;select&lt;/code&gt; blocks, and WaitGroup waits all show up here.&lt;/p&gt;
&lt;p&gt;These two profiles overlap on mutex contention — the &lt;em&gt;mutex&lt;/em&gt; profile measures wait time on contended unlock paths, while the &lt;em&gt;block&lt;/em&gt; profile records goroutines blocking on any sync primitive (channels, &lt;code&gt;select&lt;/code&gt;, WaitGroup, Cond, &lt;em&gt;and&lt;/em&gt; mutexes). Reach for the mutex profile when you suspect lock contention specifically; reach for the block profile when goroutines are blocking somewhere and you don’t yet know where.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Requires opt-in:&lt;/strong&gt; Must call &lt;code&gt;runtime.SetBlockProfileRate(n)&lt;/code&gt; to enable. Off by default.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Service is slow but CPU is low (goroutines are waiting, not working)&lt;/li&gt;
&lt;li&gt;Suspected slow I/O paths you want to quantify&lt;/li&gt;
&lt;li&gt;Channel-based communication patterns are causing bottlenecks&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;trace&quot;&gt;Trace&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;What it measures:&lt;/strong&gt; A complete timeline of everything that happened: every goroutine’s lifecycle (created, started running, blocked, unblocked, destroyed), every GC phase, processor utilization over time, system calls. This is fundamentally different from other profiles — it’s a recording of events rather than a sample.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How to think about it:&lt;/strong&gt; All other profiles are statistical summaries. The trace is a recording. If CPU profile is like “we measured CPU usage every 10ms and averaged it,” the trace is “here is the exact sequence of everything that happened, with microsecond timestamps.”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cost:&lt;/strong&gt; The trace has significantly higher overhead (~10-20% vs 1-5% for pprof) and generates large files. For a 5-second trace on a busy service, you might get a 100MB file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Latency spikes that don’t show up in CPU profiles (because the goroutine was sleeping, not running)&lt;/li&gt;
&lt;li&gt;You suspect GC pauses are causing tail latency issues&lt;/li&gt;
&lt;li&gt;Understanding scheduler behavior — why goroutines aren’t getting CPU time&lt;/li&gt;
&lt;li&gt;Diagnosing GOMAXPROCS-related issues&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;setting-up-profiling-in-your-service&quot;&gt;Setting Up Profiling in Your Service&lt;/h2&gt;
&lt;p&gt;There are three main ways to collect profiles. Which one you use depends on what you’re profiling.&lt;/p&gt;
&lt;h3 id=&quot;method-1-http-endpoint-best-for-services&quot;&gt;Method 1: HTTP Endpoint (Best for Services)&lt;/h3&gt;
&lt;p&gt;The most common and practical setup. Import &lt;code&gt;net/http/pprof&lt;/code&gt; and it registers a set of HTTP handlers automatically under &lt;code&gt;/debug/pprof/&lt;/code&gt;. You then collect profiles on-demand from a running service — either locally, in staging, or in production.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;package&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;net/http&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    _ &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;net/http/pprof&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt; // THIS is the key line — side-effect import registers handlers&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // Option A: single server (simpler, but exposes pprof on your main port)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    mux &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; http.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;NewServeMux&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    mux.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;HandleFunc&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;/api/users&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, handleUsers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // pprof handlers are already registered on http.DefaultServeMux&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // so if you&apos;re using DefaultServeMux, they&apos;re already available&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // Option B: separate debug server on a different port (RECOMMENDED)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // This way profiling never reaches your public-facing load balancer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    go&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; func&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;        // Only bind to localhost — never 0.0.0.0 for the debug server&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        log.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Println&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;Debug server listening on localhost:6060&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; http.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;ListenAndServe&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;localhost:6060&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;); err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;            log.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Printf&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;debug server error: &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;%v&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, err)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // Your real service&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    log.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Println&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;Service listening on :8080&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    log.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Fatal&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(http.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;ListenAndServe&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;:8080&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, mux))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Why a separate port?&lt;/strong&gt; Security. The &lt;code&gt;/debug/pprof/&lt;/code&gt; endpoint exposes information about your running program — goroutine stacks, memory contents (through goroutine dumps). You don’t want this accessible from the internet. By binding the debug server to &lt;code&gt;localhost:6060&lt;/code&gt;, only someone with SSH access to the machine (or on the same internal network) can reach it.&lt;/p&gt;
&lt;p&gt;After this setup, every endpoint is available:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;GET /debug/pprof/              → Index page (links to all profiles)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;GET /debug/pprof/profile       → CPU profile (default 30s, ?seconds=N to change)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;GET /debug/pprof/heap          → Heap snapshot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;GET /debug/pprof/allocs        → Allocs profile&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;GET /debug/pprof/goroutine     → Goroutine dump&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;GET /debug/pprof/mutex         → Mutex contention profile&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;GET /debug/pprof/block         → Block profile&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;GET /debug/pprof/trace         → Execution trace (?seconds=N)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;GET /debug/pprof/threadcreate  → Thread creation profile&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;GET /debug/pprof/cmdline       → Command line of the process&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;GET /debug/pprof/symbol        → Look up symbol names by address&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Collecting a CPU profile from a live service:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# This collects 30 seconds of CPU data and opens an interactive session&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; http://localhost:6060/debug/pprof/profile?seconds=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;30&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Or download first, analyze later (useful for remote servers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; cpu.out&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;http://localhost:6060/debug/pprof/profile?seconds=30&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; cpu.out&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Collecting a heap profile:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Snapshot right now&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap.out&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;http://localhost:6060/debug/pprof/heap&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -inuse_space&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap.out&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;method-2-using-the-framework-integration-if-you-use-one&quot;&gt;Method 2: Using the Framework Integration (If You Use One)&lt;/h3&gt;
&lt;p&gt;If your service uses a web framework, there are usually packages to wire pprof in cleanly:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// With gorilla/mux:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;github.com/gorilla/mux&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;net/http/pprof&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; registerDebugRoutes&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;mux&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Router&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    r.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;PathPrefix&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;/debug/pprof/&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;HandlerFunc&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(pprof.Index)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    r.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;HandleFunc&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;/debug/pprof/cmdline&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, pprof.Cmdline)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    r.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;HandleFunc&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;/debug/pprof/profile&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, pprof.Profile)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    r.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;HandleFunc&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;/debug/pprof/symbol&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, pprof.Symbol)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    r.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;HandleFunc&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;/debug/pprof/trace&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, pprof.Trace)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;method-3-programmatic-profiling-for-clis-and-tests&quot;&gt;Method 3: Programmatic Profiling (For CLIs and Tests)&lt;/h3&gt;
&lt;p&gt;For programs that don’t have an HTTP server, or when you want to profile a specific code path directly:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;package&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;os&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;runtime&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;runtime/pprof&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // --- Start CPU profiling ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    cpuFile, err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; os.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Create&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;cpu.out&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;        panic&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(err)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    defer&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; cpuFile.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Close&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pprof.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;StartCPUProfile&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(cpuFile); err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;        panic&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(err)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    defer&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pprof.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;StopCPUProfile&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// IMPORTANT: must call this before program exits&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // --- Do your work here ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    doExpensiveWork&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // --- Take a heap snapshot ---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // Force a GC first so the snapshot reflects only actually-live objects,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // not objects that have been allocated but not yet collected&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    runtime.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;GC&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    memFile, err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; os.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Create&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;mem.out&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;        panic&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(err)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    defer&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; memFile.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Close&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pprof.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;WriteHeapProfile&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(memFile); err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;        panic&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(err)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;defer pprof.StopCPUProfile()&lt;/code&gt; is critical. If your program calls &lt;code&gt;os.Exit&lt;/code&gt; or panics without recover, deferred calls don’t run and the profile file will be incomplete. Normal &lt;code&gt;main&lt;/code&gt; returns are fine.&lt;/p&gt;
&lt;h3 id=&quot;method-4-benchmark-profiles&quot;&gt;Method 4: Benchmark Profiles&lt;/h3&gt;
&lt;p&gt;For tight loops or functions you’re actively optimizing, benchmark profiling is the most precise approach:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// user_test.go&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;package&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; user&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;encoding/json&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;testing&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; User&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; struct&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    ID       &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;    `json:&quot;id&quot;`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    Name     &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; `json:&quot;name&quot;`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    Email    &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; `json:&quot;email&quot;`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    Bio      &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; `json:&quot;bio&quot;`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; BenchmarkMarshalUser&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;testing&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;B&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    u &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; User&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        ID:    &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;42&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        Name:  &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;Abhimanyu Nagurkar&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        Email: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;a@example.com&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        Bio:   &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;Software engineer, builder, dad.&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    b.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;ReportAllocs&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Show allocations per operation in the benchmark output&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    b.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;ResetTimer&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()   &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Don&apos;t count setup time in the benchmark&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;; i &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; b.N; i&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        _, err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; json.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Marshal&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(u)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;            b.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Fatal&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(err)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // In Go 1.24+, prefer `for b.Loop()` — equivalent and clearer.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run and collect:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Run benchmark and collect both CPU and memory profiles&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; test&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -bench=BenchmarkMarshalUser&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        -benchmem&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        -cpuprofile=cpu.out&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        -memprofile=mem.out&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        -count=3&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;        ./...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# The -benchmem flag makes b.ReportAllocs() output visible even without pprof&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Output:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# BenchmarkMarshalUser-8   1000000   1087 ns/op   232 B/op   4 allocs/op&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;#                          ^          ^             ^           ^&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;#                          iterations  time/op      bytes       allocs&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;allocs/op&lt;/code&gt; number is the key signal for memory optimization. 4 allocations per marshal operation means every single marshal call touches the GC 4 times. If you’re marshaling thousands of responses per second, that’s millions of allocations per second creating GC pressure.&lt;/p&gt;
&lt;h3 id=&quot;enabling-mutex-and-block-profiling&quot;&gt;Enabling Mutex and Block Profiling&lt;/h3&gt;
&lt;p&gt;These two are opt-in because they have measurable overhead. Add this somewhere early in your program:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;package&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;net/http&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    _ &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;net/http/pprof&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;runtime&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // Mutex profiling: record 1 in every N mutex contention events&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // Lower N = more data but more overhead&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // 0 = disabled (default)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // 1 = record every single contention (use only in dev/staging)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // 5 = record 20% of contentions (reasonable for staging)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    runtime.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;SetMutexProfileFraction&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // Block profiling: SetBlockProfileRate(rate) controls sampling.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // The runtime samples a blocking event with probability duration / rate —&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // so passing 1 records every event, passing 1_000_000 (1 ms) makes events&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // shorter than 1 ms increasingly rare in the profile.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // Larger values mean less overhead but coarser data.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // 0 = disabled (default)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // 1 = record every single blocking event (high overhead — dev only)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // 1000 = sample at 1us granularity (reasonable for staging)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // 1000000 = sample at 1ms granularity (safe for production)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    runtime.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;SetBlockProfileRate&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1000000&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    go&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; func&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        http.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;ListenAndServe&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;localhost:6060&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // ... rest of your server&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Production safety guidance:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mutex fraction of &lt;code&gt;5&lt;/code&gt; (20% sampling) is generally safe in production — you’ll miss some contentions but you’ll find the hot ones.&lt;/li&gt;
&lt;li&gt;Block rate of &lt;code&gt;1000000&lt;/code&gt; (1 ms granularity) is safe in production. &lt;code&gt;SetBlockProfileRate(rate)&lt;/code&gt; controls sampling: the runtime samples a blocking event with probability &lt;code&gt;duration / rate&lt;/code&gt; — so passing &lt;code&gt;1&lt;/code&gt; records every event, passing &lt;code&gt;1_000_000&lt;/code&gt; (1 ms) makes events shorter than 1 ms increasingly rare in the profile. Larger values mean less overhead but coarser data.&lt;/li&gt;
&lt;li&gt;Heap profiling is always on — no opt-in needed, though you can control the sampling rate with &lt;code&gt;runtime.MemProfileRate&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;tagging-profiles-with-labels&quot;&gt;Tagging Profiles with Labels&lt;/h3&gt;
&lt;p&gt;When a service handles multiple kinds of work, an unlabeled CPU profile mixes everything together. &lt;code&gt;runtime/pprof.Do&lt;/code&gt; lets you attach labels to a goroutine’s profile samples so you can later filter by them.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;runtime/pprof&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; handleRequest&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;ctx&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; context&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Context&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Request&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    pprof.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Do&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(ctx, pprof.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Labels&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;endpoint&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, req.Path, &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;tenant&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, req.TenantID), &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;ctx&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; context&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Context&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;        // all CPU samples and most heap allocations under this call&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;        // get tagged with endpoint=... and tenant=...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;        process&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(ctx, req)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In &lt;code&gt;pprof&lt;/code&gt;, filter with &lt;code&gt;tags&lt;/code&gt; and &lt;code&gt;tagfocus&lt;/code&gt;/&lt;code&gt;tagignore&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -tagfocus=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;endpoint=/api/users&quot;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; cpu.out&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Labels are essential when you want to know “which endpoint is dominating CPU?” instead of just “what function?”.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;reading-profiles-the-cpu-profile&quot;&gt;Reading Profiles: The CPU Profile&lt;/h2&gt;
&lt;p&gt;Let’s walk through reading a CPU profile in full detail. This is the most important skill to develop.&lt;/p&gt;
&lt;h3 id=&quot;starting-an-interactive-session&quot;&gt;Starting an Interactive Session&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; http://localhost:6060/debug/pprof/profile?seconds=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;30&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After 30 seconds of collection, you’ll see:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Fetching profile over HTTP from http://localhost:6060/debug/pprof/profile?seconds=30&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Saved profile in /home/user/pprof/pprof.samples.cpu.001.pb.gz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;File: myservice&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Type: cpu&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Time: Apr 21 2026 10:30:00 UTC (30s)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Duration: 30s, Total samples = 2.8s (9.33%)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Entering interactive mode (type &quot;help&quot; for commands, &quot;o&quot; for options)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A few things to notice:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Total samples = 2.8s&lt;/code&gt; — out of 30 seconds of wall clock time, the profiler captured 2.8 seconds of actual CPU time across all goroutines. This makes sense if you have, say, 4 goroutines all actively doing work.&lt;/li&gt;
&lt;li&gt;The file is saved locally so you can re-analyze it later without re-collecting.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;the-top-command&quot;&gt;The &lt;code&gt;top&lt;/code&gt; Command&lt;/h3&gt;
&lt;p&gt;Type &lt;code&gt;top&lt;/code&gt; or &lt;code&gt;top10&lt;/code&gt; to see the hottest functions:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) top10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Showing nodes accounting for 2.41s, 86.07% of 2.8s total&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Dropped 45 nodes (cum &amp;#x3C;= 14ms)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Showing top 10 nodes out of 87&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      flat  flat%   sum%        cum   cum%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     1.20s 42.86% 42.86%      1.20s 42.86%  syscall.Syscall&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     0.60s 21.43% 64.29%      1.80s 64.29%  runtime.mallocgc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     0.22s  7.86% 72.14%      0.22s  7.86%  encoding/json.Marshal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     0.18s  6.43% 78.57%      0.50s 17.86%  db.(*Rows).Next&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     0.12s  4.29% 82.86%      0.12s  4.29%  runtime.gcBgMarkWorker&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     0.05s  1.79% 84.64%      1.05s 37.50%  main.(*Handler).ServeHTTP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     0.03s  1.07% 85.71%      0.60s 21.43%  main.fetchUsers&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     0.01s  0.36% 86.07%      0.01s  0.36%  sync.(*Mutex).Lock&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s dissect every column:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;flat&lt;/code&gt; and &lt;code&gt;flat%&lt;/code&gt;&lt;/strong&gt;: Time spent executing &lt;em&gt;inside this function itself&lt;/em&gt; — not in any function it calls. When &lt;code&gt;flat&lt;/code&gt; is high, this function is doing the work directly. &lt;code&gt;syscall.Syscall&lt;/code&gt; at 1.20s flat means the program spent 1.20 seconds actually executing the syscall instruction. Note that &lt;code&gt;encoding/json.Marshal&lt;/code&gt; at 0.22s flat means Marshal itself (not counting the functions it calls internally) used 0.22s.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;sum%&lt;/code&gt;&lt;/strong&gt;: Running total of &lt;code&gt;flat%&lt;/code&gt;. After &lt;code&gt;syscall.Syscall&lt;/code&gt; (42.86%) and &lt;code&gt;mallocgc&lt;/code&gt; (21.43%), we’ve accounted for 64.29% of the total CPU time. This helps you know when you’ve found “enough” — once &lt;code&gt;sum%&lt;/code&gt; hits 80-90%, you’ve identified the dominant work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;cum&lt;/code&gt; and &lt;code&gt;cum%&lt;/code&gt;&lt;/strong&gt;: Cumulative time — the time spent &lt;em&gt;in this function and all functions it calls&lt;/em&gt;. &lt;code&gt;main.(*Handler).ServeHTTP&lt;/code&gt; has only 0.05s flat but 1.05s cum. That means ServeHTTP itself barely does any work — it just calls other functions (like &lt;code&gt;fetchUsers&lt;/code&gt;, which calls &lt;code&gt;db.(*Rows).Next&lt;/code&gt;, etc.) and those sub-functions are where the time is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The key insight:&lt;/strong&gt; When you see high &lt;code&gt;cum&lt;/code&gt; with low &lt;code&gt;flat&lt;/code&gt;, the function is a dispatcher — it calls things, it doesn’t do things. Follow the call tree down to find the function with high &lt;code&gt;flat&lt;/code&gt;. That’s your target.&lt;/p&gt;
&lt;p&gt;Sorting options:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) top10 -flat    # sort by flat time (default)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) top10 -cum     # sort by cumulative time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) top10 -name    # sort alphabetically&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;the-list-command&quot;&gt;The &lt;code&gt;list&lt;/code&gt; Command&lt;/h3&gt;
&lt;p&gt;Once you’ve identified a suspicious function, &lt;code&gt;list&lt;/code&gt; shows you the source code with per-line timing:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) list fetchUsers&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Total: 2.8s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ROUTINE ======================== main.fetchUsers in /home/user/service/handler.go&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      30ms      600ms (flat, cum) 21.43% of Total&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     45:func (h *Handler) fetchUsers(ctx context.Context, filter string) ([]User, error) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     46:    query := fmt.Sprintf(&quot;SELECT id, name, email FROM users WHERE name LIKE &apos;%%%s%%&apos;&quot;, filter)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      10ms       10ms     47:    rows, err := h.db.QueryContext(ctx, query)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     48:    if err != nil {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     49:        return nil, err&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     50:    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     51:    defer rows.Close()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     52:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     53:    var users []User&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      10ms      550ms     54:    for rows.Next() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     55:        var u User&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      10ms       10ms     56:        if err := rows.Scan(&amp;#x26;u.ID, &amp;#x26;u.Name, &amp;#x26;u.Email); err != nil {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     57:            return nil, err&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     58:        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     59:        users = append(users, u)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     60:    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     61:    return users, nil&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     62:}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The dot &lt;code&gt;.&lt;/code&gt; means no samples were recorded at that line. Line 54 (&lt;code&gt;rows.Next()&lt;/code&gt;) shows 550ms cumulative — the iteration over the result set is where most time goes. This tells you the database round-trips (fetching rows, network I/O) are the bottleneck, not the Go code.&lt;/p&gt;
&lt;p&gt;Also notice line 46: &lt;code&gt;fmt.Sprintf&lt;/code&gt; to build the SQL query with &lt;code&gt;%%%s%%&lt;/code&gt;. This is a format string building a LIKE query. Every call to this function allocates a new string. For a high-traffic endpoint, this is unnecessary. A parameterized query would be faster and also safer (no SQL injection risk).&lt;/p&gt;
&lt;h3 id=&quot;the-web-command--real-cpu-call-graph&quot;&gt;The &lt;code&gt;web&lt;/code&gt; Command — Real CPU Call Graph&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) web&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This opens a call graph in your browser. Each box is a function, arrow weight represents time flowing through that call, and box size corresponds to &lt;code&gt;flat&lt;/code&gt; time. Below is the actual pprof call graph generated from the benchmark above:&lt;/p&gt;
&lt;figure class=&quot;pprof-embed&quot;&gt;
  &lt;object data=&quot;/pprof/pprof-cpu-callgraph.svg&quot; type=&quot;image/svg+xml&quot; aria-label=&quot;Real pprof CPU call graph&quot;&gt;
    &lt;a href=&quot;/pprof/pprof-cpu-callgraph.svg&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Open CPU call graph (SVG)&lt;/a&gt;
  &lt;/object&gt;
  &lt;figcaption&gt;Real pprof CPU call graph — generated with &lt;code&gt;go tool pprof -svg cpu.out&lt;/code&gt;. Click and drag to pan, scroll to zoom.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In the graph, the large red/pink boxes are the hot functions. The &lt;code&gt;runtime&lt;/code&gt; nodes (scheduler, GC) dominate because the benchmark allocates heavily enough to keep the GC constantly working — itself a signal that allocation rate is too high. The &lt;code&gt;demo.buildReportSlow&lt;/code&gt; and &lt;code&gt;encoding/json.Marshal&lt;/code&gt; boxes connect into &lt;code&gt;runtime.mallocgc&lt;/code&gt;, showing the allocation chain clearly.&lt;/p&gt;
&lt;h3 id=&quot;the-flame-graph-the-most-useful-visualization&quot;&gt;The Flame Graph: The Most Useful Visualization&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -http=:8090&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; cpu.out&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This opens a web UI with multiple views including the flame graph. The flame graph is often the best way to understand a profile at a glance.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       ┌─────── json.Marshal ──────┐ ┌── strconv.AppendInt ──┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ┌─────────────── main.encodeResponse ───────────────────────────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; ┌──────────────────────── main.(*Handler).ServeHTTP ────────────────────────────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; ┌──────────────────────────────── net/http.(*conn).serve ─────────────────────────────────────────────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; ←─────────────────────────────────────────── 2.8s total ─────────────────────────────────────────────────→&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Reading a flame graph:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The X-axis represents total time. The Y-axis represents call stack depth. The bottom of the chart is the entry point (root functions like &lt;code&gt;net/http&lt;/code&gt; server code or &lt;code&gt;main&lt;/code&gt;). As you go up, you go deeper into the call stack.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Width = time.&lt;/strong&gt; A function that takes up a wide horizontal area is consuming a lot of CPU time. A narrow bar means it’s fast or rarely called.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The flat top is where the work happens.&lt;/strong&gt; When a function bar has nothing above it — no caller higher in the stack — that’s a leaf function. It’s where the CPU is actually executing instructions. Wide leaf functions are your optimization targets.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Plateaus indicate hot spots.&lt;/strong&gt; If you see a “plateau” — a wide flat area at a certain height with nothing above it — that’s a function spending CPU time directly. Clicking on it in the interactive view will highlight all call paths that lead to it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thin slivers mean fast functions.&lt;/strong&gt; A very thin vertical bar means a function is either fast or called infrequently. Ignore these.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The color doesn’t mean hot vs cold in pprof’s default flame graph&lt;/strong&gt; — it’s just used to distinguish different call paths visually. (Some flame graph tools like Brendan Gregg’s flamegraph.pl do use red for hot functions, but pprof uses color categorically.)&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;reading-profiles-the-heap-profile&quot;&gt;Reading Profiles: The Heap Profile&lt;/h2&gt;
&lt;p&gt;Memory profiles require a slightly different mental model from CPU profiles. You’re not asking “where does time go?” — you’re asking “where is memory being held, and who put it there?”&lt;/p&gt;
&lt;p&gt;Before diving into the commands, it helps to understand what the heap profile is actually recording.&lt;/p&gt;
&lt;h3 id=&quot;what-the-heap-profile-records&quot;&gt;What the Heap Profile Records&lt;/h3&gt;
&lt;p&gt;Every time your Go program allocates memory on the heap, the runtime has an opportunity to record that allocation. By default, the runtime samples allocations on average once per 512 KB allocated (probabilistic, not deterministic per-512KB; controlled by &lt;code&gt;runtime.MemProfileRate&lt;/code&gt;). Each sample captures the call stack at the point of allocation — so the profile tells you not just &lt;em&gt;how much&lt;/em&gt; memory is alive, but &lt;em&gt;which function allocated it and how it was called&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This is important: the heap profile attributes memory to the function that &lt;em&gt;allocated&lt;/em&gt; it, not necessarily the function that’s &lt;em&gt;using&lt;/em&gt; it. If &lt;code&gt;json.Marshal&lt;/code&gt; allocates a &lt;code&gt;[]byte&lt;/code&gt; that gets passed up the call stack and stored somewhere, the heap profile will show &lt;code&gt;json.Marshal&lt;/code&gt; as the allocating function — even though the long-lived reference is held somewhere higher up.&lt;/p&gt;
&lt;h3 id=&quot;the-four-heap-profile-views&quot;&gt;The Four Heap Profile Views&lt;/h3&gt;
&lt;p&gt;Every heap profile file contains four distinct datasets. You choose which one to view with a flag:&lt;/p&gt;






























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Flag&lt;/th&gt;&lt;th&gt;What it shows&lt;/th&gt;&lt;th&gt;Best used for&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-inuse_space&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Bytes currently live on the heap&lt;/td&gt;&lt;td&gt;Debugging high RSS / memory usage&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-inuse_objects&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Count of objects currently live&lt;/td&gt;&lt;td&gt;Finding which types are numerous&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-alloc_space&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Total bytes allocated since program start&lt;/td&gt;&lt;td&gt;Debugging GC pressure, high allocation rate&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-alloc_objects&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Total allocation count since program start&lt;/td&gt;&lt;td&gt;Finding frequently-allocated types&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap.out&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;http://localhost:6060/debug/pprof/heap&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -inuse_space&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;   heap.out&lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;   # default view&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -inuse_objects&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap.out&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -alloc_space&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;   heap.out&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -alloc_objects&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap.out&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;understanding-inuse_space-vs-alloc_space&quot;&gt;Understanding inuse_space vs alloc_space&lt;/h3&gt;
&lt;p&gt;This distinction trips up nearly everyone the first time. Let’s be very concrete with a story.&lt;/p&gt;
&lt;p&gt;Imagine your HTTP service has been running for 1 hour. During that hour, it processed 100,000 requests. Each request allocated a &lt;code&gt;[]byte&lt;/code&gt; response buffer of about 50KB, used it, and the GC later freed it. It also built a cache that now holds 200MB of user data.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;alloc_space&lt;/code&gt; would show the response buffer allocations prominently: &lt;code&gt;100,000 × 50KB = ~5GB&lt;/code&gt; total allocated over the hour. The cache allocations would also appear here.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;inuse_space&lt;/code&gt; would show mainly the cache: the response buffers are all gone (freed), so only the 200MB of live cache data appears.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;alloc_space (total ever allocated):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   5.00GB   main.buildResponseBuffer   &amp;#x3C;-- huge, but all freed&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   0.20GB   main.(*UserCache).populate&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;inuse_space (alive right now):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   0.20GB   main.(*UserCache).populate &amp;#x3C;-- this is what&apos;s in memory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   0.00GB   main.buildResponseBuffer   &amp;#x3C;-- gone, GC freed it&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Rule of thumb:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;High RSS / OOM / &lt;code&gt;kubectl top&lt;/code&gt; shows too much memory → use &lt;code&gt;-inuse_space&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;High CPU from GC / many GC cycles per second / slow allocation-heavy path → use &lt;code&gt;-alloc_space&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both tell you something real. Sometimes you need both to get the full picture.&lt;/p&gt;
&lt;h3 id=&quot;collecting-and-opening&quot;&gt;Collecting and Opening&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Take a snapshot of the heap right now&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap.out&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;http://localhost:6060/debug/pprof/heap&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Open interactively&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -inuse_space&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap.out&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Or open the web UI with flame graph&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -http=:8090&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -inuse_space&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap.out&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To force a GC before snapshotting heap, call &lt;code&gt;runtime.GC()&lt;/code&gt; from inside the process (or via a small admin endpoint you add yourself) — there is no built-in pprof endpoint that triggers GC. In your Go code:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;runtime&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;runtime/pprof&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Force GC so the snapshot reflects only truly-live objects&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;runtime.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;GC&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;f, _ &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; os.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Create&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;heap.out&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;defer&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; f.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Close&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;pprof.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;WriteHeapProfile&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(f)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;real-profile-output-what-youll-actually-see&quot;&gt;Real Profile Output: What You’ll Actually See&lt;/h3&gt;
&lt;p&gt;The outputs below are real — generated by running a benchmark with intentional allocation hot spots using &lt;code&gt;go test -bench=BenchmarkAll -benchmem -cpuprofile=cpu.out -memprofile=mem.out&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The benchmark exercises three patterns:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;buildReportSlow&lt;/code&gt;&lt;/strong&gt;: builds a string with &lt;code&gt;+=&lt;/code&gt; in a loop — O(n²) allocations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;marshalSlow&lt;/code&gt;&lt;/strong&gt;: calls &lt;code&gt;json.Marshal&lt;/code&gt; which allocates a full &lt;code&gt;[]byte&lt;/code&gt; on each call&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;processUsers&lt;/code&gt;&lt;/strong&gt;: calls &lt;code&gt;fmt.Sprintf&lt;/code&gt; per user to build labels&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Benchmark results&lt;/strong&gt; — this is what you see before even opening pprof:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;BenchmarkBuildReportSlow-11    40176    89214 ns/op    844161 B/op     800 allocs/op&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;BenchmarkBuildReportFast-11   187976    19255 ns/op     20008 B/op     402 allocs/op&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;BenchmarkMarshalSlow-11       161523    22209 ns/op     18496 B/op       2 allocs/op&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;BenchmarkMarshalFast-11       153967    23324 ns/op     41026 B/op       4 allocs/op&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;BenchmarkProcessUsers-11       69067    52088 ns/op     30093 B/op    1746 allocs/op&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;BenchmarkAll-11                22957   157441 ns/op    914053 B/op    1407 allocs/op&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;BenchmarkBuildReportSlow&lt;/code&gt; at &lt;strong&gt;800 allocs/op&lt;/strong&gt; and &lt;strong&gt;844KB per call&lt;/strong&gt; vs &lt;code&gt;BenchmarkBuildReportFast&lt;/code&gt; at &lt;strong&gt;402 allocs/op&lt;/strong&gt; and &lt;strong&gt;20KB per call&lt;/strong&gt; — the &lt;code&gt;strings.Builder&lt;/code&gt; version uses 42× less memory per call. The &lt;code&gt;-benchmem&lt;/code&gt; flag gives you this for free, before you even open pprof.&lt;/p&gt;
&lt;h3 id=&quot;reading-the-top-output-for-heap&quot;&gt;Reading the top Output for Heap&lt;/h3&gt;
&lt;p&gt;Running &lt;code&gt;go tool pprof -alloc_space mem.out&lt;/code&gt; then &lt;code&gt;top10 -cum&lt;/code&gt; on the real profile above:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Type: alloc_space&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Duration: 8.11s, Total samples = 36577.85MB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      flat  flat%   sum%        cum   cum%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         0     0%     0%  36574.14MB   100%  demo.BenchmarkAll&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         0     0%     0%  36574.14MB   100%  testing.(*B).runN&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         0     0%     0%  36573.14MB   100%  testing.(*B).launch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;32935.27MB 90.04% 90.04%  33339.32MB 91.15%  demo.buildReportSlow&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    0.50MB  0.00% 90.04%   2782.90MB  7.61%  demo.marshalSlow (inline)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; 1558.32MB  4.26% 94.30%   2782.40MB  7.61%  encoding/json.Marshal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    0.00MB  0.00% 94.30%   1191.54MB  3.26%  encoding/json.(*encodeState).marshal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    0.00MB  0.00% 94.30%   1191.54MB  3.26%  encoding/json.arrayEncoder.encode&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    0.00MB  0.00% 94.30%   1191.54MB  3.26%  encoding/json.sliceEncoder.encode&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  266.42MB  0.73% 95.03%    451.92MB  1.24%  demo.processUsers&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;flat&lt;/code&gt; and &lt;code&gt;cum&lt;/code&gt; columns work the same as in CPU profiles, but measure memory instead of time:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;demo.buildReportSlow&lt;/code&gt;&lt;/strong&gt; has 32,935MB flat — it &lt;em&gt;directly&lt;/em&gt; allocated nearly 33GB worth of string data over the benchmark run. This is the string concatenation &lt;code&gt;+=&lt;/code&gt; in a loop, each iteration copying the entire accumulated string into a new allocation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;demo.marshalSlow&lt;/code&gt;&lt;/strong&gt; has only 0.50MB flat but 2,782MB cum — &lt;code&gt;marshalSlow&lt;/code&gt; itself allocates almost nothing, but it calls &lt;code&gt;json.Marshal&lt;/code&gt; which allocates the full response &lt;code&gt;[]byte&lt;/code&gt; on every call. The 0.50MB flat is just the slice header.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;encoding/json.Marshal&lt;/code&gt;&lt;/strong&gt; at 1,558MB flat — these are the actual &lt;code&gt;[]byte&lt;/code&gt; response buffers being allocated fresh each time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;demo.processUsers&lt;/code&gt;&lt;/strong&gt; at 266MB flat — all those &lt;code&gt;fmt.Sprintf&lt;/code&gt; calls building label strings.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The pattern to read: high &lt;code&gt;flat&lt;/code&gt; = this is the allocation site. High &lt;code&gt;cum&lt;/code&gt;, low &lt;code&gt;flat&lt;/code&gt; = this function is a caller that owns the cost indirectly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sorting and filtering:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) top10 -cum         # show by cumulative (understand call chain ownership)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) top10 -flat        # show by direct allocation (find the actual allocating line)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) top -cum -n 20     # top 20 by cum&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Start with &lt;code&gt;-cum&lt;/code&gt; to find which part of the call tree is responsible, then switch to &lt;code&gt;-flat&lt;/code&gt; to find the exact function doing the allocating.&lt;/p&gt;
&lt;h3 id=&quot;drilling-into-source-with-list&quot;&gt;Drilling Into Source with list&lt;/h3&gt;
&lt;p&gt;Once &lt;code&gt;top&lt;/code&gt; points you at a function, &lt;code&gt;list&lt;/code&gt; shows the exact lines:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) list buildReportSlow&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Total: 36577.85MB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ROUTINE ======================== demo.buildReportSlow&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   32.16GB    32.56GB (flat, cum) 91.15% of Total&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     23:func buildReportSlow(users []User) string {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     24:    result := &quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     25:    for _, u := range users {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     26:        // Each + allocates a new string&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   32.16GB    32.56GB     27:        result += fmt.Sprintf(&quot;User %d: %s &amp;#x3C;%s&gt;\n&quot;, u.ID, u.Name, u.Email)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     28:    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     29:    return result&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     30:}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Line 27 is the entire problem — &lt;strong&gt;32GB&lt;/strong&gt; attributed to one line (this is total bytes allocated and freed across all benchmark iterations, not memory live at any one moment). Every &lt;code&gt;+=&lt;/code&gt; on a string in Go creates a brand new string by copying the old string plus the new suffix. With 200 users, that’s 200 copies of increasing length: copy 0 chars, copy ~40 chars, copy ~80 chars, … copy ~8000 chars. Total work is O(n²) in the length of the result.&lt;/p&gt;
&lt;p&gt;The tree output confirms the call chain:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) tree buildReportSlow&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;----------------------------------------------------------+-------------&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      flat  flat%   sum%        cum  cum%   calls calls% + context&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;----------------------------------------------------------+-------------&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                               33339.32MB 100% |   demo.BenchmarkAll&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;32935.27MB 90.04% 90.04%  33339.32MB 91.15%   |   demo.buildReportSlow&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                                 404.06MB  1.21% |     fmt.Sprintf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;----------------------------------------------------------+-------------&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                                 404.06MB 100% |   demo.buildReportSlow&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  368.02MB  1.01% 91.05%    404.06MB  1.10%   |   fmt.Sprintf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;----------------------------------------------------------+-------------&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;buildReportSlow&lt;/code&gt; owns 90% of all allocations. &lt;code&gt;fmt.Sprintf&lt;/code&gt; inside it accounts for another 404MB (the intermediate formatted strings). The string concatenation itself — the &lt;code&gt;+=&lt;/code&gt; — is the 32GB, because every loop iteration copies all previous output.&lt;/p&gt;
&lt;h3 id=&quot;real-memory-call-graph&quot;&gt;Real Memory Call Graph&lt;/h3&gt;
&lt;p&gt;Here is the actual &lt;code&gt;go tool pprof -alloc_space -svg mem.out&lt;/code&gt; output from the same benchmark — a real memory call graph, not a diagram:&lt;/p&gt;
&lt;figure class=&quot;pprof-embed&quot;&gt;
  &lt;object data=&quot;/pprof/pprof-mem-callgraph.svg&quot; type=&quot;image/svg+xml&quot; aria-label=&quot;Real pprof memory call graph&quot;&gt;
    &lt;a href=&quot;/pprof/pprof-mem-callgraph.svg&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Open memory call graph (SVG)&lt;/a&gt;
  &lt;/object&gt;
  &lt;figcaption&gt;Real pprof memory call graph — generated with &lt;code&gt;go tool pprof -alloc_space -svg mem.out&lt;/code&gt;. Click and drag to pan, scroll to zoom.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;code&gt;demo.buildReportSlow&lt;/code&gt; dominates the graph at 90% of total allocations — its box is the largest. The arrows flow down into &lt;code&gt;fmt.Sprintf&lt;/code&gt; and &lt;code&gt;runtime.mallocgc&lt;/code&gt;. &lt;code&gt;encoding/json.Marshal&lt;/code&gt; is the second cluster. The relative box sizes make the 90/8/2 split visible at a glance.&lt;/p&gt;
&lt;p&gt;To generate this yourself from any profile:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -alloc_space&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -svg&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; mem.out&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; mem-callgraph.svg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -svg&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; cpu.out&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; cpu-callgraph.svg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Requires &lt;a href=&quot;https://graphviz.org&quot;&gt;Graphviz&lt;/a&gt; (&lt;code&gt;brew install graphviz&lt;/code&gt; on macOS).&lt;/p&gt;
&lt;h3 id=&quot;using-the-heap-flame-graph&quot;&gt;Using the Heap Flame Graph&lt;/h3&gt;
&lt;p&gt;The interactive flame graph is the fastest way to see the allocation picture at a glance. Run:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -http=:8090&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -alloc_space&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; mem.out&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your browser opens at &lt;code&gt;localhost:8090&lt;/code&gt;. Click &lt;strong&gt;Flame Graph&lt;/strong&gt; in the top nav. For the profile above, you’d see a single dominant bar — &lt;code&gt;buildReportSlow&lt;/code&gt; taking up ~90% of the horizontal width, with &lt;code&gt;marshalSlow&lt;/code&gt;/&lt;code&gt;json.Marshal&lt;/code&gt; occupying the remaining ~8%. The overwhelming width of &lt;code&gt;buildReportSlow&lt;/code&gt; makes the problem impossible to miss visually; you don’t even need to read the numbers.&lt;/p&gt;
&lt;p&gt;Here’s the real pprof flame graph captured from running this exact benchmark:&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;/pprof/flamechart-mem.png&quot; alt=&quot;pprof memory flame graph showing buildReportSlow dominating ~90% of allocated memory&quot; style=&quot;width:100%;border-radius:8px;border:1px solid rgb(var(--gray-light));&quot;&gt;
  &lt;figcaption style=&quot;font-size:0.8rem;color:rgb(var(--gray));margin-top:0.4rem;&quot;&gt;Real pprof flame graph (alloc_space) — &lt;code&gt;demo.buildReportSlow&lt;/code&gt; is the wide bar on the left, &lt;code&gt;demo.marshalSlow&lt;/code&gt;/&lt;code&gt;json.Marshal&lt;/code&gt; on the right. Width = allocated bytes.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In the web UI, the flame graph for heap profiles reads exactly like the CPU flame graph, but width = memory. A wide bar means that call path is responsible for a lot of allocated memory.&lt;/p&gt;
&lt;p&gt;Switch between views in the top navigation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Flame graph&lt;/strong&gt;: visual call tree&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: the &lt;code&gt;top&lt;/code&gt; table&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Source&lt;/strong&gt;: annotated source (same as &lt;code&gt;list&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Peek&lt;/strong&gt;: shows callers of a function&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One particularly useful feature: in the flame graph, you can click a function bar to filter the view to only that function’s subtree. This helps when a big allocator like &lt;code&gt;json.Marshal&lt;/code&gt; appears in many call paths — you can isolate just the path you care about.&lt;/p&gt;
&lt;h3 id=&quot;the--base-flag-finding-what-grew&quot;&gt;The &lt;code&gt;-base&lt;/code&gt; Flag: Finding What Grew&lt;/h3&gt;
&lt;p&gt;The most powerful technique for tracking memory leaks is taking two snapshots and comparing them. The diff tells you exactly what grew — not what’s large in general, but what’s &lt;em&gt;larger now than before&lt;/em&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Step 1: take the first snapshot before the suspected leak period&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap1.out&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;http://localhost:6060/debug/pprof/heap&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;Snapshot 1 at $(&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Step 2: let the service run for a while under normal traffic&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# The leak will accumulate during this time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Step 3: take the second snapshot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap2.out&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;http://localhost:6060/debug/pprof/heap&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;Snapshot 2 at $(&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Step 4: diff them — what grew?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -inuse_space&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -base&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap1.out&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap2.out&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output now shows deltas — positive numbers mean that function is holding more memory in snapshot 2:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) top10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Showing nodes accounting for +52.40MB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      flat  flat%   sum%        cum   cum%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  +42.00MB 80.15% 80.15%  +42.00MB 80.15%  main.(*EventStore).Append&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  +10.40MB 19.85% 100.00%  +52.40MB 100.00%  main.(*MetricsCollector).Record&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you see a function with steadily growing positive values across multiple snapshots taken over time, that’s your leak.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Taking periodic snapshots automatically:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For production leak investigations, a simple shell loop works well:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    curl&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;heap_&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$i&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;.out&quot;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;http://prod-host:6060/debug/pprof/heap&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;Snapshot &lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$i&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; at $(&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    sleep&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 300&lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;  # 5 minutes between snapshots&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Then compare snapshot 1 vs 5 to see total growth&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -inuse_space&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -base&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap_1.out&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap_5.out&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# And compare consecutive snapshots to see the rate of growth&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -inuse_space&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -base&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap_1.out&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap_2.out&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -inuse_space&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -base&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap_2.out&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap_3.out&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the growth is consistent across consecutive diffs, the leak is active throughout. If only some diffs show growth, the leak might be triggered by a specific condition (a particular request type, time-of-day behavior, etc.).&lt;/p&gt;
&lt;h3 id=&quot;understanding-memory-profile-sampling&quot;&gt;Understanding Memory Profile Sampling&lt;/h3&gt;
&lt;p&gt;Heap profiling is not 100% complete — it’s sampled. By default, the runtime samples allocations on average once per 512 KB allocated (probabilistic, not deterministic per-512KB). This means small allocations that happen infrequently might not appear in the profile.&lt;/p&gt;
&lt;p&gt;You can lower the sampling threshold to catch smaller allocations:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;runtime&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; init&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // Record every single allocation (maximum detail, higher overhead)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // Default is 512*1024 (512KB)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    runtime.MemProfileRate &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Setting &lt;code&gt;MemProfileRate = 1&lt;/code&gt; means every allocation is recorded. This is useful when investigating a suspected small-object leak that isn’t showing up in the default profile, but it increases overhead significantly and should only be used for targeted debugging, not in production.&lt;/p&gt;
&lt;h3 id=&quot;what-rss-vs-heap-means-and-why-they-differ&quot;&gt;What “RSS vs Heap” Means and Why They Differ&lt;/h3&gt;
&lt;p&gt;One thing that confuses people: the heap profile might show 200MB live but your process’s RSS (resident set size — what &lt;code&gt;top&lt;/code&gt; or &lt;code&gt;kubectl top&lt;/code&gt; reports) might be 400MB. Why the gap?&lt;/p&gt;
&lt;p&gt;Several reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Go runtime overhead&lt;/strong&gt;: The Go scheduler, goroutine stacks, internal runtime structures, and metadata all consume memory that doesn’t show up in the heap profile.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stack memory&lt;/strong&gt;: Each goroutine has a stack. 1,000 goroutines × 8KB minimum stack = 8MB just in stacks. Stacks can grow much larger.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory fragmentation&lt;/strong&gt;: The OS allocates memory in pages (typically 4KB or larger). Even if your heap objects total 200MB, the OS might have mapped 250MB of pages to the process.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Go’s memory retention&lt;/strong&gt;: Go doesn’t immediately return freed memory to the OS. After the GC frees objects, the memory stays in Go’s heap arena until the OS explicitly needs it back or until &lt;code&gt;runtime.FreeOSMemory()&lt;/code&gt; is called (or &lt;code&gt;MADV_FREE&lt;/code&gt;/&lt;code&gt;MADV_DONTNEED&lt;/code&gt; is used on Linux).&lt;/li&gt;
&lt;/ol&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.6.9&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 1339 303&quot;&gt;&lt;svg class=&quot;d2-816269920 d2-svg&quot; width=&quot;1339&quot; height=&quot;303&quot; viewBox=&quot;-25 -36 1339 303&quot;&gt;&lt;rect x=&quot;-25.000000&quot; y=&quot;-36.000000&quot; width=&quot;1339.000000&quot; height=&quot;303.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-816269920 .text {
	font-family: &quot;d2-816269920-font-regular&quot;;
}
@font-face {
	font-family: d2-816269920-font-regular;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-816269920 .text-bold {
	font-family: &quot;d2-816269920-font-bold&quot;;
}
@font-face {
	font-family: d2-816269920-font-bold;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-816269920 .fill-N1{fill:#0A0F25;}
		.d2-816269920 .fill-N2{fill:#676C7E;}
		.d2-816269920 .fill-N3{fill:#9499AB;}
		.d2-816269920 .fill-N4{fill:#CFD2DD;}
		.d2-816269920 .fill-N5{fill:#DEE1EB;}
		.d2-816269920 .fill-N6{fill:#EEF1F8;}
		.d2-816269920 .fill-N7{fill:#FFFFFF;}
		.d2-816269920 .fill-B1{fill:#0D32B2;}
		.d2-816269920 .fill-B2{fill:#0D32B2;}
		.d2-816269920 .fill-B3{fill:#E3E9FD;}
		.d2-816269920 .fill-B4{fill:#E3E9FD;}
		.d2-816269920 .fill-B5{fill:#EDF0FD;}
		.d2-816269920 .fill-B6{fill:#F7F8FE;}
		.d2-816269920 .fill-AA2{fill:#4A6FF3;}
		.d2-816269920 .fill-AA4{fill:#EDF0FD;}
		.d2-816269920 .fill-AA5{fill:#F7F8FE;}
		.d2-816269920 .fill-AB4{fill:#EDF0FD;}
		.d2-816269920 .fill-AB5{fill:#F7F8FE;}
		.d2-816269920 .stroke-N1{stroke:#0A0F25;}
		.d2-816269920 .stroke-N2{stroke:#676C7E;}
		.d2-816269920 .stroke-N3{stroke:#9499AB;}
		.d2-816269920 .stroke-N4{stroke:#CFD2DD;}
		.d2-816269920 .stroke-N5{stroke:#DEE1EB;}
		.d2-816269920 .stroke-N6{stroke:#EEF1F8;}
		.d2-816269920 .stroke-N7{stroke:#FFFFFF;}
		.d2-816269920 .stroke-B1{stroke:#0D32B2;}
		.d2-816269920 .stroke-B2{stroke:#0D32B2;}
		.d2-816269920 .stroke-B3{stroke:#E3E9FD;}
		.d2-816269920 .stroke-B4{stroke:#E3E9FD;}
		.d2-816269920 .stroke-B5{stroke:#EDF0FD;}
		.d2-816269920 .stroke-B6{stroke:#F7F8FE;}
		.d2-816269920 .stroke-AA2{stroke:#4A6FF3;}
		.d2-816269920 .stroke-AA4{stroke:#EDF0FD;}
		.d2-816269920 .stroke-AA5{stroke:#F7F8FE;}
		.d2-816269920 .stroke-AB4{stroke:#EDF0FD;}
		.d2-816269920 .stroke-AB5{stroke:#F7F8FE;}
		.d2-816269920 .background-color-N1{background-color:#0A0F25;}
		.d2-816269920 .background-color-N2{background-color:#676C7E;}
		.d2-816269920 .background-color-N3{background-color:#9499AB;}
		.d2-816269920 .background-color-N4{background-color:#CFD2DD;}
		.d2-816269920 .background-color-N5{background-color:#DEE1EB;}
		.d2-816269920 .background-color-N6{background-color:#EEF1F8;}
		.d2-816269920 .background-color-N7{background-color:#FFFFFF;}
		.d2-816269920 .background-color-B1{background-color:#0D32B2;}
		.d2-816269920 .background-color-B2{background-color:#0D32B2;}
		.d2-816269920 .background-color-B3{background-color:#E3E9FD;}
		.d2-816269920 .background-color-B4{background-color:#E3E9FD;}
		.d2-816269920 .background-color-B5{background-color:#EDF0FD;}
		.d2-816269920 .background-color-B6{background-color:#F7F8FE;}
		.d2-816269920 .background-color-AA2{background-color:#4A6FF3;}
		.d2-816269920 .background-color-AA4{background-color:#EDF0FD;}
		.d2-816269920 .background-color-AA5{background-color:#F7F8FE;}
		.d2-816269920 .background-color-AB4{background-color:#EDF0FD;}
		.d2-816269920 .background-color-AB5{background-color:#F7F8FE;}
		.d2-816269920 .color-N1{color:#0A0F25;}
		.d2-816269920 .color-N2{color:#676C7E;}
		.d2-816269920 .color-N3{color:#9499AB;}
		.d2-816269920 .color-N4{color:#CFD2DD;}
		.d2-816269920 .color-N5{color:#DEE1EB;}
		.d2-816269920 .color-N6{color:#EEF1F8;}
		.d2-816269920 .color-N7{color:#FFFFFF;}
		.d2-816269920 .color-B1{color:#0D32B2;}
		.d2-816269920 .color-B2{color:#0D32B2;}
		.d2-816269920 .color-B3{color:#E3E9FD;}
		.d2-816269920 .color-B4{color:#E3E9FD;}
		.d2-816269920 .color-B5{color:#EDF0FD;}
		.d2-816269920 .color-B6{color:#F7F8FE;}
		.d2-816269920 .color-AA2{color:#4A6FF3;}
		.d2-816269920 .color-AA4{color:#EDF0FD;}
		.d2-816269920 .color-AA5{color:#F7F8FE;}
		.d2-816269920 .color-AB4{color:#EDF0FD;}
		.d2-816269920 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-816269920);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-816269920);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-816269920);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-816269920);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-816269920);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-816269920);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-816269920);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-816269920);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-816269920);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-816269920);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-816269920);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-816269920);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-816269920);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-816269920);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-816269920);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-816269920);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-816269920);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-816269920);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;cHJvY2Vzcw==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;0.000000&quot; y=&quot;29.000000&quot; width=&quot;1289.000000&quot; height=&quot;213.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#E3E9FD&quot; class=&quot;stroke-B1 fill-B4&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;644.500000&quot; y=&quot;16.000000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:28px&quot;&gt;Process RSS&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;cHJvY2Vzcy5oZWFw&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;30.000000&quot; y=&quot;70.000000&quot; width=&quot;484.000000&quot; height=&quot;142.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;272.000000&quot; y=&quot;58.000000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:24px&quot;&gt;Go Heap Arena&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;cHJvY2Vzcy5zdGFja3M=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;564.000000&quot; y=&quot;100.000000&quot; width=&quot;175.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;651.500000&quot; y=&quot;138.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;651.500000&quot; dy=&quot;0.000000&quot;&gt;Goroutine Stacks&lt;/tspan&gt;&lt;tspan x=&quot;651.500000&quot; dy=&quot;18.500000&quot;&gt;not in heap profile&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;cHJvY2Vzcy5ydW50aW1lX2ludGVybmFs&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;799.000000&quot; y=&quot;100.000000&quot; width=&quot;209.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;903.500000&quot; y=&quot;138.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;903.500000&quot; dy=&quot;0.000000&quot;&gt;Runtime internals&lt;/tspan&gt;&lt;tspan x=&quot;903.500000&quot; dy=&quot;18.500000&quot;&gt;scheduler GC metadata&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;cHJvY2Vzcy5jZ28=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;1068.000000&quot; y=&quot;100.000000&quot; width=&quot;191.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;1163.500000&quot; y=&quot;138.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;1163.500000&quot; dy=&quot;0.000000&quot;&gt;cgo allocations&lt;/tspan&gt;&lt;tspan x=&quot;1163.500000&quot; dy=&quot;18.500000&quot;&gt;not tracked by pprof&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;cHJvY2Vzcy5oZWFwLmxpdmU=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;60.000000&quot; y=&quot;100.000000&quot; width=&quot;198.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;159.000000&quot; y=&quot;138.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;159.000000&quot; dy=&quot;0.000000&quot;&gt;Live Objects&lt;/tspan&gt;&lt;tspan x=&quot;159.000000&quot; dy=&quot;18.500000&quot;&gt;shown in inuse_space&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;cHJvY2Vzcy5oZWFwLmRlYWQ=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;318.000000&quot; y=&quot;100.000000&quot; width=&quot;166.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;401.000000&quot; y=&quot;138.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;401.000000&quot; dy=&quot;0.000000&quot;&gt;Freed but not yet&lt;/tspan&gt;&lt;tspan x=&quot;401.000000&quot; dy=&quot;18.500000&quot;&gt;returned to OS&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;mask id=&quot;d2-816269920&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-25&quot; y=&quot;-36&quot; width=&quot;1339&quot; height=&quot;303&quot;&gt;
&lt;rect x=&quot;-25&quot; y=&quot;-36&quot; width=&quot;1339&quot; height=&quot;303&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;574.500000&quot; y=&quot;-12.000000&quot; width=&quot;140&quot; height=&quot;36&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;198.500000&quot; y=&quot;34.000000&quot; width=&quot;147&quot; height=&quot;31&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;586.500000&quot; y=&quot;122.500000&quot; width=&quot;130&quot; height=&quot;37&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;821.500000&quot; y=&quot;122.500000&quot; width=&quot;164&quot; height=&quot;37&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;1090.500000&quot; y=&quot;122.500000&quot; width=&quot;146&quot; height=&quot;37&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;82.500000&quot; y=&quot;122.500000&quot; width=&quot;153&quot; height=&quot;37&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;340.500000&quot; y=&quot;122.500000&quot; width=&quot;121&quot; height=&quot;37&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;If you need to shrink RSS without reducing actual live memory, you can call &lt;code&gt;debug.FreeOSMemory()&lt;/code&gt;, which forces the runtime to return unused heap pages to the OS. This is a one-shot operation though — it doesn’t change the long-term allocation pattern.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;runtime/debug&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Force return of unused memory pages to the OS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Rarely needed — the runtime handles this automatically over time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;debug.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;FreeOSMemory&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;using-runtimemetrics-for-continuous-monitoring&quot;&gt;Using runtime/metrics for Continuous Monitoring&lt;/h3&gt;
&lt;p&gt;Instead of taking snapshots manually, you can expose heap metrics continuously via &lt;code&gt;runtime/metrics&lt;/code&gt; (Go 1.16+):&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;package&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;runtime/metrics&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; printHeapStats&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // Define which metrics you want&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    samples &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; []&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;metrics&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Sample&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        {Name: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;/memory/classes/heap/objects:bytes&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;},   &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// live heap objects&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        {Name: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;/memory/classes/heap/released:bytes&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;},  &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// released to OS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        {Name: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;/memory/classes/heap/free:bytes&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;},      &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// free but retained&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        {Name: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;/gc/heap/allocs:bytes&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;},                 &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// cumulative allocs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        {Name: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;/gc/cycles/total:gc-cycles&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;},            &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// total GC cycles&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    metrics.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Read&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(samples)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; _, s &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; samples {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; s.Value.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Kind&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; metrics.KindUint64 {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;            fmt.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Printf&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;%s&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;%d\n&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, s.Name, s.Value.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Uint64&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Exposing these as Prometheus or Datadog metrics gives you continuous visibility without needing to collect pprof snapshots. You’d typically alert on &lt;code&gt;heap/objects:bytes&lt;/code&gt; growing without bound over days, and then use pprof snapshots to investigate the cause once the alert fires.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;reading-profiles-goroutine-dumps&quot;&gt;Reading Profiles: Goroutine Dumps&lt;/h2&gt;
&lt;p&gt;The goroutine profile is different from CPU and heap — it’s not a statistical sample. It’s an instant snapshot of every goroutine that exists right now, with their complete call stacks.&lt;/p&gt;
&lt;h3 id=&quot;collecting&quot;&gt;Collecting&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# debug=1: just goroutine counts per state&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;http://localhost:6060/debug/pprof/goroutine?debug=1&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# debug=2: full stack traces for every goroutine (this is what you want)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;http://localhost:6060/debug/pprof/goroutine?debug=2&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;what-a-goroutine-dump-looks-like&quot;&gt;What a Goroutine Dump Looks Like&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;goroutine 1 [running]:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;main.main()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    /home/user/service/main.go:42 +0x1a4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;goroutine 18 [sleep]:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;time.Sleep(0x77359400)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    /usr/local/go/src/runtime/time.go:195 +0xd2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;main.backgroundJob()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    /home/user/service/jobs.go:23 +0x45&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;created by main.startJobs in goroutine 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    /home/user/service/main.go:38 +0x6e&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;goroutine 23 [chan receive]:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;main.processQueue(0xc00012a000)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    /home/user/service/worker.go:45 +0x89&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;created by main.startWorkers in goroutine 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    /home/user/service/main.go:52 +0xb2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;goroutine 24 [chan receive]:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;main.processQueue(0xc00012a000)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    /home/user/service/worker.go:45 +0x89&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;created by main.startWorkers in goroutine 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    /home/user/service/main.go:52 +0xb2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;... (200 more goroutines in exactly the same state)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The goroutine state is the critical signal.&lt;/strong&gt; Each goroutine shows its current state in brackets:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[running]&lt;/code&gt; — currently executing on a CPU&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[sleep]&lt;/code&gt; — in &lt;code&gt;time.Sleep()&lt;/code&gt; or similar&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[chan receive]&lt;/code&gt; — blocked waiting for a channel to have data&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[chan send]&lt;/code&gt; — blocked waiting for a channel to accept data&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[IO wait]&lt;/code&gt; — blocked on I/O (network, file)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[semacquire]&lt;/code&gt; — waiting to acquire a mutex or semaphore&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[select]&lt;/code&gt; — blocked in a &lt;code&gt;select&lt;/code&gt; statement&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[syscall]&lt;/code&gt; — executing a system call&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;What to look for:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Goroutine count that’s unexpectedly high.&lt;/strong&gt; A healthy service might have hundreds of goroutines — one per active HTTP connection, some for background jobs, some for the runtime itself. But if you see 10,000 goroutines and you have only 100 active requests, something is leaking.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Many goroutines in the same state at the same call stack.&lt;/strong&gt; If you see 500 goroutines all sitting at &lt;code&gt;chan receive&lt;/code&gt; on the exact same line, that’s a single channel nobody is reading from. Everything that tries to write to it blocks.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Goroutines stuck in &lt;code&gt;syscall&lt;/code&gt; state for a long time.&lt;/strong&gt; System calls should be brief. A goroutine that’s been in &lt;code&gt;syscall&lt;/code&gt; for a long time (seconds) is likely doing a blocking network operation with no timeout.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;created by X&lt;/code&gt; pointing to the same place.&lt;/strong&gt; If you see thousands of goroutines all created by the same function, that function is creating goroutines faster than they’re completing.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;goroutine-leak-example&quot;&gt;Goroutine Leak Example&lt;/h3&gt;
&lt;p&gt;Here’s a classic goroutine leak pattern and what it looks like in a dump:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// BUGGY CODE: this leaks a goroutine every time processRequest is called&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; processRequest&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Request&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    resultCh &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; make&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;chan&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Result&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)  &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// unbuffered channel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    go&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; func&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        result &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; doExpensiveWork&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(req)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        resultCh &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; result  &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// THIS BLOCKS if nobody reads the channel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    select&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    case&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; &amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;resultCh:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;        sendResponse&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(result)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    case&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; &amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;time.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;After&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; time.Millisecond):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;        sendTimeout&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;        // We return here but the goroutine is still running, blocked on resultCh &amp;#x3C;- result&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;        // Nobody will ever read from resultCh now&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;        // The goroutine is leaked&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;        return&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the goroutine dump, you’d see hundreds of goroutines like:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;goroutine 1842 [chan send, 45 minutes]:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;main.processRequest.func1()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    /home/user/service/handler.go:67 +0x94&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;created by main.processRequest in goroutine 1234&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    /home/user/service/handler.go:62 +0x4e&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;45 minutes&lt;/code&gt; shows how long the goroutine has been blocked — a clear sign it’s stuck forever.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; processRequest&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Request&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // Use a context with timeout so the goroutine gets a signal to stop&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    ctx, cancel &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; context.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;WithTimeout&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(context.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Background&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(), &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;time.Millisecond)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    defer&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; cancel&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// This signals the goroutine even if we return early&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    resultCh &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; make&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;chan&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Result&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Buffered — goroutine can always send&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    go&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; func&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        result &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; doExpensiveWork&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(ctx, req) &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Pass ctx so work can abort&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;        select&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;        case&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; resultCh &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; result:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;        case&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; &amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;ctx.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Done&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(): &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// If timeout happened, don&apos;t block&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    select&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    case&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; &amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;resultCh:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;        sendResponse&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(result)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    case&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; &amp;#x3C;-&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;ctx.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Done&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;        sendTimeout&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;reading-profiles-the-execution-trace&quot;&gt;Reading Profiles: The Execution Trace&lt;/h2&gt;
&lt;p&gt;The trace is the most powerful profiling tool but also the most complex to interpret. Use it when other profiles haven’t given you the answer.&lt;/p&gt;
&lt;h3 id=&quot;collecting-and-opening-1&quot;&gt;Collecting and Opening&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Collect 5 seconds of trace (use a short window — files get large fast)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; trace.out&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;http://localhost:6060/debug/pprof/trace?seconds=5&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Open in browser&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; trace&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; trace.out&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This opens a browser UI at &lt;code&gt;http://localhost:PORT/&lt;/code&gt; with several views.&lt;/p&gt;
&lt;h3 id=&quot;the-views-and-what-they-tell-you&quot;&gt;The Views and What They Tell You&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Goroutine analysis&lt;/strong&gt; — This shows time breakdown per goroutine across five states:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Execution&lt;/strong&gt; time: goroutine was running on a CPU&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Network wait&lt;/strong&gt;: goroutine was waiting for network I/O&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sync block&lt;/strong&gt;: goroutine was waiting on a mutex/channel/semaphore&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scheduler wait&lt;/strong&gt;: goroutine was ready to run but waiting for a CPU slot&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GC&lt;/strong&gt; time: goroutine was paused or helping with GC&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A goroutine with 10% Execution and 80% Sync block is spending most of its time waiting — likely for a slow database or a contested lock.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;View trace&lt;/strong&gt; — The raw timeline view. You see:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All goroutines as horizontal lanes&lt;/li&gt;
&lt;li&gt;Color indicates state (running, blocked, network wait, etc.)&lt;/li&gt;
&lt;li&gt;GC events shown as spans that overlay the goroutine timeline&lt;/li&gt;
&lt;li&gt;You can zoom in to microsecond resolution&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you see periodic “gaps” across all goroutines at the same time — that’s a GC stop-the-world pause. The length of that gap is your STW pause latency.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Minimum Mutator Utilization (MMU)&lt;/strong&gt; — This chart directly answers “what percentage of the time was my code actually running (as opposed to being stopped for GC)?” The Y-axis is utilization (1.0 = 100% of time running), the X-axis is window size (looking at any N-second window, what’s the minimum utilization?). If the MMU at 1ms is 0.80, it means in the worst case, your code was only running 80% of the time in any 1ms window — 20% was GC pauses.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;mutex-and-block-profiles-in-detail&quot;&gt;Mutex and Block Profiles in Detail&lt;/h2&gt;
&lt;h3 id=&quot;mutex-profile-1&quot;&gt;Mutex Profile&lt;/h3&gt;
&lt;p&gt;After enabling with &lt;code&gt;runtime.SetMutexProfileFraction(5)&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; http://localhost:6060/debug/pprof/mutex&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) top5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Showing nodes accounting for 8.50s, 95.25% of 8.92s total&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      flat  flat%   sum%        cum   cum%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     4.20s 47.09% 47.09%      4.20s 47.09%  sync.(*Mutex).Unlock&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     2.10s 23.54% 70.63%      6.30s 70.63%  main.(*Cache).Get&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     1.50s 16.82% 87.45%      1.50s 16.82%  main.(*Cache).Set&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The times here represent how long &lt;em&gt;other goroutines waited&lt;/em&gt; because of contention on this mutex. &lt;code&gt;Cache.Get&lt;/code&gt; causing 6.3s of contention means goroutines collectively waited 6.3 seconds trying to acquire the cache’s lock.&lt;/p&gt;
&lt;p&gt;The fix pattern: if reads far outnumber writes, switch from &lt;code&gt;sync.Mutex&lt;/code&gt; to &lt;code&gt;sync.RWMutex&lt;/code&gt; and use &lt;code&gt;RLock()&lt;/code&gt;/&lt;code&gt;RUnlock()&lt;/code&gt; for reads. Multiple goroutines can hold an &lt;code&gt;RLock&lt;/code&gt; simultaneously — only writers need exclusive access.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Before: every operation, read or write, blocks everyone&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Cache&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; struct&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    mu    &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sync&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Mutex&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    items &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;string&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;c &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Cache&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Get&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) (&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    c.mu.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Lock&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    defer&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; c.mu.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Unlock&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    v, ok &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; c.items[key]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; v, ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// After: reads can happen concurrently, only writes are exclusive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Cache&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; struct&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    mu    &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sync&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;RWMutex&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    items &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;string&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;c &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Cache&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Get&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) (&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    c.mu.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;RLock&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()         &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Multiple goroutines can hold RLock simultaneously&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    defer&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; c.mu.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;RUnlock&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    v, ok &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; c.items[key]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; v, ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;c &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Cache&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Set&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    c.mu.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Lock&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()          &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Only one writer at a time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    defer&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; c.mu.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Unlock&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    c.items[key] &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;block-profile-1&quot;&gt;Block Profile&lt;/h3&gt;
&lt;p&gt;After enabling with &lt;code&gt;runtime.SetBlockProfileRate(1)&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; http://localhost:6060/debug/pprof/block&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) top5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Showing nodes accounting for 15.2s, 87.36% of 17.4s total&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      flat  flat%   sum%        cum   cum%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     8.40s 48.28% 48.28%      8.40s 48.28%  main.(*DB).query&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     4.20s 24.14% 72.41%      4.20s 24.14%  runtime.selectgo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     2.10s 12.07% 84.48%      2.10s 12.07%  sync.(*WaitGroup).Wait&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;DB.query&lt;/code&gt; blocking 8.4s means goroutines spent 8.4 seconds waiting in that function. Combined with looking at the source code, this usually means waiting on a connection pool (not enough connections available) or slow query results.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;runtime.selectgo&lt;/code&gt; blocking means goroutines are blocking in &lt;code&gt;select&lt;/code&gt; statements — either waiting for a channel or a timeout. This might be expected (workers waiting for jobs) or a sign of slow producers.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;common-scenarios-step-by-step-walkthroughs&quot;&gt;Common Scenarios: Step-by-Step Walkthroughs&lt;/h2&gt;
&lt;h3 id=&quot;scenario-1-the-everything-is-slow-investigation&quot;&gt;Scenario 1: The “Everything Is Slow” Investigation&lt;/h3&gt;
&lt;p&gt;You get a report: “The API is slow.” P50 is 200ms, P99 is 2 seconds. CPU is at 60%. Where do you start?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: CPU profile first&lt;/strong&gt; because CPU is elevated.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Generate some load first (use hey, wrk, or k6)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;hey&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 10000&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -c&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 50&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; http://localhost:8080/api/users&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# In another terminal, collect the profile&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; http://localhost:6060/debug/pprof/profile?seconds=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;30&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) top10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      flat  flat%   sum%        cum   cum%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     1.80s 64.29% 64.29%      1.80s 64.29%  runtime.mallocgc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     0.40s 14.29% 78.57%      0.40s 14.29%  encoding/json.Marshal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     0.30s 10.71% 89.29%      2.50s 89.29%  main.(*Handler).getUsers&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;mallocgc&lt;/code&gt; is the garbage collector’s allocation function. It being at 64% means the program is spending most of its CPU time allocating memory, not doing actual work. This is GC pressure — the allocation rate is so high that the GC can’t keep up.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Find what’s allocating.&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Get the allocs profile (not heap — allocs shows total allocation rate)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; http://localhost:6060/debug/pprof/allocs&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) top10 -alloc_space&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      flat  flat%   sum%        cum   cum%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  1.20GB 48.00% 48.00%    1.20GB 48.00%  encoding/json.Marshal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  0.80GB 32.00% 80.00%    2.00GB 80.00%  main.(*Handler).getUsers&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  0.30GB 12.00% 92.00%    0.30GB 12.00%  fmt.Sprintf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;json.Marshal&lt;/code&gt; is allocating 1.2GB total (this is over the 30 second period). For 10,000 requests, that’s 120KB of allocation per request just for JSON serialization.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3: List the hot function.&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) list getUsers&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     .     1.2GB     78:    data, err := json.Marshal(users)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every request is marshaling a potentially large &lt;code&gt;users&lt;/code&gt; slice into JSON from scratch. Fixes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use &lt;code&gt;json.NewEncoder(w).Encode(users)&lt;/code&gt; — streams directly to the response writer, avoids allocating the &lt;code&gt;[]byte&lt;/code&gt; intermediate&lt;/li&gt;
&lt;li&gt;If the data is cacheable, cache the serialized result&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;sync.Pool&lt;/code&gt; for the encoder itself&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Step 4: Implement, re-profile, confirm.&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Before&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;h &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Handler&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;getUsers&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;w&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; http&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;ResponseWriter&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Request&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    users, _ &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; h.store.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;ListUsers&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    data, err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; json.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Marshal&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(users)    &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// allocates a []byte&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        http.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Error&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(w, err.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Error&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(), &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;500&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;        return&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    w.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Header&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Set&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;application/json&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    w.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Write&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(data)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// After&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;h &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Handler&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;getUsers&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;w&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; http&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;ResponseWriter&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Request&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    users, _ &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; h.store.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;ListUsers&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    w.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Header&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Set&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;application/json&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // json.NewEncoder streams to w directly — no intermediate allocation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; json.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;NewEncoder&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(w).&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Encode&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(users); err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;        // Can&apos;t set status code here (headers already sent), so log it&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        log.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Printf&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;encode error: &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;%v&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, err)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Re-profile and compare. The &lt;code&gt;mallocgc&lt;/code&gt; entry should drop significantly.&lt;/p&gt;
&lt;h3 id=&quot;scenario-2-memory-leak-investigation&quot;&gt;Scenario 2: Memory Leak Investigation&lt;/h3&gt;
&lt;p&gt;You notice your service’s memory usage grows by about 50MB per hour and never comes back down. The service runs fine for a day but needs to be restarted weekly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Capture two snapshots separated by time.&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Capture the first snapshot (note the time)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap1.out&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;http://localhost:6060/debug/pprof/heap&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;Snapshot 1 taken at $(&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Wait 1 hour, or until you see significant memory growth&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sleep&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 3600&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Capture the second snapshot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap2.out&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;http://localhost:6060/debug/pprof/heap&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;Snapshot 2 taken at $(&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;)&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Compare.&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -inuse_space&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -base&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap1.out&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap2.out&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) top5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Showing nodes accounting for +52.40MB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      flat  flat%   sum%        cum   cum%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  +42.00MB 80.15% 80.15%  +42.00MB 80.15%  main.(*EventStore).Append&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  +10.40MB 19.85% 100.00%  +52.40MB 100.00%  main.(*MetricsCollector).Record&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;EventStore.Append&lt;/code&gt; grew by 42MB. This is your leak.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Inspect the code.&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Probable buggy code&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; EventStore&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; struct&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    events []&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Event&lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;  // this slice grows unboundedly&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    mu     &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sync&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Mutex&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;s &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;EventStore&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Append&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Event&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    s.mu.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Lock&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    defer&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; s.mu.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Unlock&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    s.events &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; append&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(s.events, e)  &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// never trimmed, never rotated&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;events&lt;/code&gt; slice keeps all events forever with no eviction, rotation, or size limit.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fix options:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Keep only the last N events with a ring buffer&lt;/li&gt;
&lt;li&gt;Write events to an external store (database, message queue) and don’t keep them in memory&lt;/li&gt;
&lt;li&gt;Add a TTL-based eviction: periodically trim events older than some duration&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;scenario-3-diagnosing-p99-latency-spikes&quot;&gt;Scenario 3: Diagnosing p99 Latency Spikes&lt;/h3&gt;
&lt;p&gt;P50 is 10ms, P99 is 500ms. The requests that are slow seem random — no pattern in the payload. CPU is low, memory is stable. This is a classic GC pause pattern.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Capture a trace during load.&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Apply load&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;hey&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 5000&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -c&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; http://localhost:8080/api/data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Capture trace simultaneously (5 second window is usually enough)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; trace.out&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;http://localhost:6060/debug/pprof/trace?seconds=5&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; trace&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; trace.out&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the browser, open &lt;strong&gt;“View trace”&lt;/strong&gt; and zoom in on the timeline. Look for moments where all goroutines stop simultaneously. These are GC stop-the-world pauses.&lt;/p&gt;
&lt;p&gt;You might see:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;STW mark termination: 2.3ms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;STW sweep termination: 0.1ms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;STW mark termination: 1.8ms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;... repeating every 200ms ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2.3ms STW pauses every 200ms. At 100 concurrent requests, a 2.3ms pause would cause all in-flight requests to stall. For a request that took 8ms without the pause, it now takes 10.3ms. But if a request is unlucky and hits two pauses, it takes 12.6ms. At p99, you’re seeing multiple pauses accumulate.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Check allocation rate.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the trace UI, look at &lt;strong&gt;“Goroutine analysis”&lt;/strong&gt; and look at the GC goroutines. If &lt;code&gt;gcBgMarkWorker&lt;/code&gt; is constantly present, the GC is running continuously — a sign of very high allocation rate.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Reduce allocation rate.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The most effective fix is using &lt;code&gt;sync.Pool&lt;/code&gt; for frequently-allocated objects:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Before: every request allocates a new buffer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; handleRequest&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;w&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; http&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;ResponseWriter&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Request&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    buf &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;bytes&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Buffer&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)  &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// new allocation every request&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    buildResponse&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(buf, r)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    w.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Write&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(buf.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Bytes&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// After: reuse buffers from a pool&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; bufPool &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; sync&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Pool&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    New: &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;any&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;bytes&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Buffer&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; handleRequest&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;w&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; http&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;ResponseWriter&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Request&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    buf &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; bufPool.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Get&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;().(&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;bytes&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Buffer&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    buf.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Reset&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()              &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// clear the buffer before use&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    defer&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; bufPool.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Put&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(buf)   &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// return to pool when done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    buildResponse&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(buf, r)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    w.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Write&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(buf.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Bytes&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;sync.Pool&lt;/code&gt; maintains a pool of objects that can be reused across goroutines. The GC clears the pool on each GC cycle (so pool objects don’t prevent garbage collection), but in the steady state between GC cycles, goroutines reuse the same buffer objects instead of allocating new ones.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4: Tune the GC target if needed.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you’ve reduced allocations and still see GC pressure, you can tune when the GC triggers:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;runtime/debug&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // GOGC controls when GC triggers. Default is 100, meaning GC triggers&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // when heap grows 100% beyond the size after the last GC.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // Setting to 200 means GC triggers less often but uses more memory.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // This is a trade-off: less GC CPU, more RAM usage.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    debug.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;SetGCPercent&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;200&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // GOMEMLIMIT (Go 1.19+) sets a soft memory limit.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // The GC will work harder to stay under this limit.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // This prevents the service from using so much memory it gets OOM-killed.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    debug.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;SetMemoryLimit&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; &amp;#x3C;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 30&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// 1 GB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // ... rest of your program&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Or via environment variables (no code change needed):&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;GOGC&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;200&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; GOMEMLIMIT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;1073741824&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; ./myservice&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;scenario-4-the-service-doesnt-scale-under-load&quot;&gt;Scenario 4: The Service Doesn’t Scale Under Load&lt;/h3&gt;
&lt;p&gt;Adding more CPUs (or increasing &lt;code&gt;GOMAXPROCS&lt;/code&gt;) doesn’t improve throughput. This suggests serialization — something is forcing work to happen one at a time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Profile: Mutex contention.&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Make sure SetMutexProfileFraction was called at startup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; http://localhost:6060/debug/pprof/mutex&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) top5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      flat  flat%   sum%        cum   cum%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    12.30s 68.33% 68.33%     12.30s 68.33%  main.(*RequestCounter).Increment&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     4.20s 23.33% 91.67%      4.20s 23.33%  main.(*RateLimiter).Allow&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;code&gt;RequestCounter&lt;/code&gt; that’s being incremented on every request from every goroutine is a global shared state with a mutex. Every goroutine contends on it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fix: Use &lt;code&gt;sync/atomic&lt;/code&gt; for simple counters.&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Before: mutex-protected counter is a bottleneck&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; RequestCounter&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; struct&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    mu    &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sync&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Mutex&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    count &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;int64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;c &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;RequestCounter&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Increment&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    c.mu.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Lock&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    c.count&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;++&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    c.mu.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Unlock&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;c &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;RequestCounter&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Get&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;int64&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    c.mu.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Lock&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    defer&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; c.mu.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Unlock&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; c.count&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// After: atomic operations require no lock&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; RequestCounter&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; struct&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    count &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;int64&lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt; // must be 64-bit aligned for atomic ops (automatic on 64-bit platforms when the field is the first in the struct; matters on 32-bit ARM/x86 if you reorder fields)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;c &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;RequestCounter&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Increment&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    atomic.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;AddInt64&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;c.count, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// lock-free, safe from multiple goroutines&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;c &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;RequestCounter&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Get&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;int64&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; atomic.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;LoadInt64&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;c.count)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For more complex shared data structures, consider &lt;strong&gt;sharding&lt;/strong&gt; — splitting one lock into N locks by key:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Instead of one global cache with one lock:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; ShardedCache&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; struct&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    shards [&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;256&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        mu    &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sync&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;RWMutex&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        items &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;string&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;c &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;ShardedCache&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;shard&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // Simple hash to pick a shard&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    h &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; fnv.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;New32a&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    h.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Write&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;([]&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;byte&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(key))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(h.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Sum32&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 256&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;c &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;ShardedCache&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Get&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) (&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    s &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; c.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;shard&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(key)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    c.shards[s].mu.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;RLock&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    defer&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; c.shards[s].mu.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;RUnlock&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    v, ok &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; c.shards[s].items[key]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; v, ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now instead of all 256 goroutines contending on a single lock, each goroutine contends with only ~1 other goroutine on average (because keys are distributed across 256 shards).&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;visual-guide-reading-flame-graphs-and-memory-diagrams&quot;&gt;Visual Guide: Reading Flame Graphs and Memory Diagrams&lt;/h2&gt;
&lt;p&gt;This section walks through what the &lt;code&gt;go tool pprof&lt;/code&gt; web UI actually looks like and how to navigate it. Since screenshots from a live pprof session depend on your specific program, the annotated diagrams below replicate the structure and layout of what you’ll see — so when you open the real UI, you’ll know exactly what you’re looking at.&lt;/p&gt;
&lt;h3 id=&quot;opening-the-web-ui&quot;&gt;Opening the Web UI&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -http=:8090&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; cpu.out&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your browser opens to &lt;code&gt;http://localhost:8090&lt;/code&gt;. The top navigation bar has these views:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[ Top ] [ Graph ] [ Flame Graph ] [ Peek ] [ Source ] [ Disassemble ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                                      ^&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                                  start here&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Top&lt;/strong&gt; — the &lt;code&gt;top&lt;/code&gt; table you’ve already seen in the interactive CLI. Good first stop.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Graph&lt;/strong&gt; — a directed call graph. Boxes are functions, arrows show call relationships, box size corresponds to &lt;code&gt;flat&lt;/code&gt; cost, arrow weight corresponds to flow. Gets cluttered on large profiles but good for seeing call relationships.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Flame Graph&lt;/strong&gt; — the flame graph. Best for understanding the full picture at a glance.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Peek&lt;/strong&gt; — shows callers of the selected function. Useful for understanding who is responsible for a hot function you didn’t write.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Source&lt;/strong&gt; — annotated source, same as the &lt;code&gt;list&lt;/code&gt; command.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;anatomy-of-a-cpu-flame-graph&quot;&gt;Anatomy of a CPU Flame Graph&lt;/h3&gt;
&lt;p&gt;Here’s what a CPU flame graph looks like for a typical HTTP service, annotated:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt; WIDE AND AT THE TOP = hot leaf function (where CPU is burning)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; │    ┌──────────────────────────────────────────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; │    │          encoding/json.(*Encoder).Encode     │  ← 38% CPU, this is hot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; │    └──────────────────────────────────────────────┘&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; │    ┌─────────────────────────────────────────────────────────────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; │    │                   main.buildAPIResponse                         │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; │    └─────────────────────────────────────────────────────────────────┘&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; │    ┌──────────────────────────────────────────────────────────────────────────────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; │    │                           main.(*Handler).ServeHTTP                              │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; │    └──────────────────────────────────────────────────────────────────────────────────┘&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; │    ┌──────────────────────────────────────────────────────────────────────────────────────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; │    │                              net/http.(*conn).serve                                       │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; │    └──────────────────────────────────────────────────────────────────────────────────────────────┘&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; ↓&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; WIDE AND AT THE BOTTOM = root of the call stack (entry point)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Key patterns to recognize:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pattern 1 — Flat top (direct hot spot)&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt; ┌────────────────────────────────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; │         syscall.RawSyscall         │  ← wide, nothing above it&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; └────────────────────────────────────┘  ← this IS the bottleneck&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; ┌─────────────────────────────────────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; │         net.(*netFD).Read               │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; └─────────────────────────────────────────┘&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; ┌──────────────────────────────────────────────────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; │             bufio.(*Reader).fill                     │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; └──────────────────────────────────────────────────────┘&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;syscall.RawSyscall&lt;/code&gt; has no children (nothing above it). The CPU is spending time executing the system call directly. The fix is either to reduce the number of syscalls (buffering, batching) or accept that I/O is the bound.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pattern 2 — Wide middle (delegating hot spot)&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                         ┌──────┐ ┌──────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                         │ fmt  │ │strco │  ← many small children&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                         └──────┘ └──────┘&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; ┌─────────────────────────────────────────────────────────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; │                  encoding/json.Marshal                       │  ← wide, has children&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; └─────────────────────────────────────────────────────────────┘&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;json.Marshal&lt;/code&gt; is wide but has children above it. The work is split across the children — you can’t optimize Marshal directly; you need to reduce how often it’s called or switch to a faster encoder.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pattern 3 — “Tall spike” (rare deep call)&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         ┌────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         │    │  ← narrow spike going deep&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         └────┘&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         │    │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         └────┘&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         │    │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         └────┘&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; ┌───────────────────────────────────────────────────────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; │                                                           │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; └───────────────────────────────────────────────────────────┘&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A narrow, tall column means a function that’s rarely called but goes deep into the call stack when it is. Usually not a performance bottleneck unless the narrow bar is also very wide (meaning it runs for a long time per call).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pattern 4 — GC work (purple/distinct color)&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt; ┌──────────────────────────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; │  runtime.gcBgMarkWorker      │  ← GC background mark worker&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; └──────────────────────────────┘&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; ┌────────────────────────────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; │  runtime.mallocgc              │  ← allocator (if wide, you have alloc pressure)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; └────────────────────────────────┘&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In pprof’s web UI, runtime functions are often shown in a distinct color. &lt;code&gt;gcBgMarkWorker&lt;/code&gt; appearing wide means the GC is doing a lot of marking — your heap is large or changing fast. &lt;code&gt;mallocgc&lt;/code&gt; wide means the allocator is being called constantly. Both are signals to investigate the allocs profile.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;anatomy-of-a-heap-flame-graph&quot;&gt;Anatomy of a Heap Flame Graph&lt;/h3&gt;
&lt;p&gt;The heap flame graph looks the same structurally, but the width represents memory, not time. Here’s an annotated version for &lt;code&gt;-inuse_space&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt; ┌───────────────────────────────────────────────────────────────────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; │              bytes.(*Buffer) internal backing array                   │  ← 412MB live&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; └───────────────────────────────────────────────────────────────────────┘&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; ┌──────────────────────────────────────────────────────────────────────────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; │                       main.buildResponse                                     │  ← 490MB cum&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; └──────────────────────────────────────────────────────────────────────────────┘&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; ┌──────────────────────────────────────────────────────────────────────────────────────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; │                            net/http.(*conn).serve                                         │  ← everything below&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; └──────────────────────────────────────────────────────────────────────────────────────────────┘&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What to look for in a heap flame graph:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Wide bars near the top&lt;/strong&gt; — the allocating functions. These are where your memory is actually coming from. If &lt;code&gt;bytes.(*Buffer).Write&lt;/code&gt; is 60% wide, 60% of your live heap is buffer backing arrays.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Runtime functions&lt;/strong&gt; — &lt;code&gt;runtime.mallocgc&lt;/code&gt;, &lt;code&gt;runtime.newobject&lt;/code&gt;, &lt;code&gt;runtime.makeslice&lt;/code&gt;, &lt;code&gt;runtime.makemap&lt;/code&gt;. If these appear prominently in the alloc view, your hot paths are allocating frequently.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Unexpected wide bars&lt;/strong&gt; — functions you didn’t expect to be allocating much. A logging library appearing with 20% of allocations is worth investigating.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The “diff” flame graph&lt;/strong&gt; — when you use &lt;code&gt;-base&lt;/code&gt;, the flame graph shows bars colored by growth: green bars shrank (less memory), red bars grew. Wide red bars are your leak candidates.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-heap-memory-flow-diagram&quot;&gt;The Heap Memory Flow Diagram&lt;/h3&gt;
&lt;p&gt;To really understand what the heap profile captures, it helps to trace the lifecycle of a single allocation through the system:&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.6.9&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 1051 1073&quot;&gt;&lt;svg class=&quot;d2-526691279 d2-svg&quot; width=&quot;1051&quot; height=&quot;1073&quot; viewBox=&quot;-13 27 1051 1073&quot;&gt;&lt;rect x=&quot;-13.000000&quot; y=&quot;27.000000&quot; width=&quot;1051.000000&quot; height=&quot;1073.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-526691279 .text {
	font-family: &quot;d2-526691279-font-regular&quot;;
}
@font-face {
	font-family: d2-526691279-font-regular;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-526691279 .text-italic {
	font-family: &quot;d2-526691279-font-italic&quot;;
}
@font-face {
	font-family: d2-526691279-font-italic;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-526691279 .fill-N1{fill:#0A0F25;}
		.d2-526691279 .fill-N2{fill:#676C7E;}
		.d2-526691279 .fill-N3{fill:#9499AB;}
		.d2-526691279 .fill-N4{fill:#CFD2DD;}
		.d2-526691279 .fill-N5{fill:#DEE1EB;}
		.d2-526691279 .fill-N6{fill:#EEF1F8;}
		.d2-526691279 .fill-N7{fill:#FFFFFF;}
		.d2-526691279 .fill-B1{fill:#0D32B2;}
		.d2-526691279 .fill-B2{fill:#0D32B2;}
		.d2-526691279 .fill-B3{fill:#E3E9FD;}
		.d2-526691279 .fill-B4{fill:#E3E9FD;}
		.d2-526691279 .fill-B5{fill:#EDF0FD;}
		.d2-526691279 .fill-B6{fill:#F7F8FE;}
		.d2-526691279 .fill-AA2{fill:#4A6FF3;}
		.d2-526691279 .fill-AA4{fill:#EDF0FD;}
		.d2-526691279 .fill-AA5{fill:#F7F8FE;}
		.d2-526691279 .fill-AB4{fill:#EDF0FD;}
		.d2-526691279 .fill-AB5{fill:#F7F8FE;}
		.d2-526691279 .stroke-N1{stroke:#0A0F25;}
		.d2-526691279 .stroke-N2{stroke:#676C7E;}
		.d2-526691279 .stroke-N3{stroke:#9499AB;}
		.d2-526691279 .stroke-N4{stroke:#CFD2DD;}
		.d2-526691279 .stroke-N5{stroke:#DEE1EB;}
		.d2-526691279 .stroke-N6{stroke:#EEF1F8;}
		.d2-526691279 .stroke-N7{stroke:#FFFFFF;}
		.d2-526691279 .stroke-B1{stroke:#0D32B2;}
		.d2-526691279 .stroke-B2{stroke:#0D32B2;}
		.d2-526691279 .stroke-B3{stroke:#E3E9FD;}
		.d2-526691279 .stroke-B4{stroke:#E3E9FD;}
		.d2-526691279 .stroke-B5{stroke:#EDF0FD;}
		.d2-526691279 .stroke-B6{stroke:#F7F8FE;}
		.d2-526691279 .stroke-AA2{stroke:#4A6FF3;}
		.d2-526691279 .stroke-AA4{stroke:#EDF0FD;}
		.d2-526691279 .stroke-AA5{stroke:#F7F8FE;}
		.d2-526691279 .stroke-AB4{stroke:#EDF0FD;}
		.d2-526691279 .stroke-AB5{stroke:#F7F8FE;}
		.d2-526691279 .background-color-N1{background-color:#0A0F25;}
		.d2-526691279 .background-color-N2{background-color:#676C7E;}
		.d2-526691279 .background-color-N3{background-color:#9499AB;}
		.d2-526691279 .background-color-N4{background-color:#CFD2DD;}
		.d2-526691279 .background-color-N5{background-color:#DEE1EB;}
		.d2-526691279 .background-color-N6{background-color:#EEF1F8;}
		.d2-526691279 .background-color-N7{background-color:#FFFFFF;}
		.d2-526691279 .background-color-B1{background-color:#0D32B2;}
		.d2-526691279 .background-color-B2{background-color:#0D32B2;}
		.d2-526691279 .background-color-B3{background-color:#E3E9FD;}
		.d2-526691279 .background-color-B4{background-color:#E3E9FD;}
		.d2-526691279 .background-color-B5{background-color:#EDF0FD;}
		.d2-526691279 .background-color-B6{background-color:#F7F8FE;}
		.d2-526691279 .background-color-AA2{background-color:#4A6FF3;}
		.d2-526691279 .background-color-AA4{background-color:#EDF0FD;}
		.d2-526691279 .background-color-AA5{background-color:#F7F8FE;}
		.d2-526691279 .background-color-AB4{background-color:#EDF0FD;}
		.d2-526691279 .background-color-AB5{background-color:#F7F8FE;}
		.d2-526691279 .color-N1{color:#0A0F25;}
		.d2-526691279 .color-N2{color:#676C7E;}
		.d2-526691279 .color-N3{color:#9499AB;}
		.d2-526691279 .color-N4{color:#CFD2DD;}
		.d2-526691279 .color-N5{color:#DEE1EB;}
		.d2-526691279 .color-N6{color:#EEF1F8;}
		.d2-526691279 .color-N7{color:#FFFFFF;}
		.d2-526691279 .color-B1{color:#0D32B2;}
		.d2-526691279 .color-B2{color:#0D32B2;}
		.d2-526691279 .color-B3{color:#E3E9FD;}
		.d2-526691279 .color-B4{color:#E3E9FD;}
		.d2-526691279 .color-B5{color:#EDF0FD;}
		.d2-526691279 .color-B6{color:#F7F8FE;}
		.d2-526691279 .color-AA2{color:#4A6FF3;}
		.d2-526691279 .color-AA4{color:#EDF0FD;}
		.d2-526691279 .color-AA5{color:#F7F8FE;}
		.d2-526691279 .color-AB4{color:#EDF0FD;}
		.d2-526691279 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-526691279);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-526691279);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-526691279);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-526691279);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-526691279);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-526691279);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-526691279);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-526691279);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-526691279);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-526691279);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-526691279);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-526691279);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-526691279);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-526691279);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-526691279);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-526691279);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-526691279);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-526691279);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;Q29kZQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;12.000000&quot; y=&quot;52.000000&quot; width=&quot;115.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;69.500000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Your Code&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;QWxsb2M=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;172.000000&quot; y=&quot;52.000000&quot; width=&quot;163.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;253.500000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;runtime.mallocgc&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;SGVhcA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;450.000000&quot; y=&quot;52.000000&quot; width=&quot;103.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;501.500000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Go Heap&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;UHJvZmlsZQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;635.000000&quot; y=&quot;52.000000&quot; width=&quot;172.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;721.000000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Heap Profile Buffer&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;R0M=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;847.000000&quot; y=&quot;52.000000&quot; width=&quot;166.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;930.000000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Garbage Collector&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KENvZGUgLS0gKVswXQ==&quot;&gt;&lt;path d=&quot;M 69.500000 120.000000 L 69.500000 1073.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-526691279)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEFsbG9jIC0tIClbMF0=&quot;&gt;&lt;path d=&quot;M 253.500000 120.000000 L 253.500000 1073.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-526691279)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEhlYXAgLS0gKVswXQ==&quot;&gt;&lt;path d=&quot;M 501.500000 120.000000 L 501.500000 1073.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-526691279)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KFByb2ZpbGUgLS0gKVswXQ==&quot;&gt;&lt;path d=&quot;M 721.000000 120.000000 L 721.000000 1073.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-526691279)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEdDIC0tIClbMF0=&quot;&gt;&lt;path d=&quot;M 930.000000 120.000000 L 930.000000 1073.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-526691279)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KENvZGUgLSZndDsgQWxsb2MpWzBd&quot;&gt;&lt;marker id=&quot;mk-d2-526691279-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 71.500000 198.000000 L 249.500000 198.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-526691279-3488378134)&quot; mask=&quot;url(#d2-526691279)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;162.000000&quot; y=&quot;204.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;make([]byte, 1024)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEFsbG9jIC0mZ3Q7IEhlYXApWzBd&quot;&gt;&lt;path d=&quot;M 255.500000 288.000000 L 497.500000 288.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-526691279-3488378134)&quot; mask=&quot;url(#d2-526691279)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;378.000000&quot; y=&quot;294.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;find or acquire memory span&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KENvZGUgJmx0Oy0gQWxsb2MpWzBd&quot;&gt;&lt;marker id=&quot;mk-d2-526691279-2864536236&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;3.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;10.000000,0.000000 0.000000,6.000000 10.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B2&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 73.500000 378.000000 L 251.500000 378.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:6.000000,5.919384;&quot; marker-start=&quot;url(#mk-d2-526691279-2864536236)&quot; mask=&quot;url(#d2-526691279)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;162.000000&quot; y=&quot;384.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;pointer to memory&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEFsbG9jIC0mZ3Q7IFByb2ZpbGUpWzBd&quot;&gt;&lt;path d=&quot;M 255.500000 476.000000 L 717.000000 476.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-526691279-3488378134)&quot; mask=&quot;url(#d2-526691279)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;487.500000&quot; y=&quot;474.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;487.500000&quot; dy=&quot;0.000000&quot;&gt;record stack trace&lt;/tspan&gt;&lt;tspan x=&quot;487.500000&quot; dy=&quot;18.500000&quot;&gt;(if sample threshold met)&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KENvZGUgJmx0Oy0gQWxsb2MpWzFd&quot;&gt;&lt;path d=&quot;M 73.500000 574.000000 L 251.500000 574.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:6.000000,5.919384;&quot; marker-start=&quot;url(#mk-d2-526691279-2864536236)&quot; mask=&quot;url(#d2-526691279)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;161.500000&quot; y=&quot;580.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;return []byte&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KENvZGUgLSZndDsgQ29kZSlbMF0=&quot;&gt;&lt;path d=&quot;M 71.500000 654.000000 L 143.000000 654.000000 S 153.000000 654.000000 153.000000 664.000000 L 153.000000 699.500000 S 153.000000 709.500000 143.000000 709.500000 L 73.500000 709.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-526691279-3488378134)&quot; mask=&quot;url(#d2-526691279)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;153.500000&quot; y=&quot;679.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;153.500000&quot; dy=&quot;0.000000&quot;&gt;function returns,&lt;/tspan&gt;&lt;tspan x=&quot;153.500000&quot; dy=&quot;18.500000&quot;&gt;slice goes out of scope&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEdDIC0mZ3Q7IEhlYXApWzBd&quot;&gt;&lt;path d=&quot;M 928.000000 789.500000 L 505.500000 789.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-526691279-3488378134)&quot; mask=&quot;url(#d2-526691279)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;715.500000&quot; y=&quot;795.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;mark phase: scan for reachable objects&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEdDIC0mZ3Q7IEhlYXApWzFd&quot;&gt;&lt;path d=&quot;M 928.000000 879.500000 L 505.500000 879.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-526691279-3488378134)&quot; mask=&quot;url(#d2-526691279)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;715.500000&quot; y=&quot;885.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;sweep phase: free unreachable objects&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEhlYXAgLSZndDsgSGVhcClbMF0=&quot;&gt;&lt;path d=&quot;M 503.500000 959.500000 L 601.000000 959.500000 S 611.000000 959.500000 611.000000 969.500000 L 611.000000 994.500000 S 611.000000 1004.500000 601.000000 1004.500000 L 505.500000 1004.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-526691279-3488378134)&quot; mask=&quot;url(#d2-526691279)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;611.500000&quot; y=&quot;988.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;memory returned to span pool&lt;/text&gt;&lt;/g&gt;&lt;mask id=&quot;d2-526691279&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-13&quot; y=&quot;27&quot; width=&quot;1051&quot; height=&quot;1073&quot;&gt;
&lt;rect x=&quot;-13&quot; y=&quot;27&quot; width=&quot;1051&quot; height=&quot;1073&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;34.500000&quot; y=&quot;74.500000&quot; width=&quot;70&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;194.500000&quot; y=&quot;74.500000&quot; width=&quot;118&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;472.500000&quot; y=&quot;74.500000&quot; width=&quot;58&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;657.500000&quot; y=&quot;74.500000&quot; width=&quot;127&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;869.500000&quot; y=&quot;74.500000&quot; width=&quot;121&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;101.000000&quot; y=&quot;188.000000&quot; width=&quot;122&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;284.000000&quot; y=&quot;278.000000&quot; width=&quot;188&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;100.000000&quot; y=&quot;368.000000&quot; width=&quot;124&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;406.000000&quot; y=&quot;458.000000&quot; width=&quot;163&quot; height=&quot;37&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;120.000000&quot; y=&quot;564.000000&quot; width=&quot;83&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;80.000000&quot; y=&quot;663.000000&quot; width=&quot;147&quot; height=&quot;37&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;587.000000&quot; y=&quot;779.000000&quot; width=&quot;257&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;588.000000&quot; y=&quot;869.000000&quot; width=&quot;255&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;512.000000&quot; y=&quot;972.000000&quot; width=&quot;199&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;This sequence explains why heap profiles can sometimes show more memory than is actually in use: the profile is sampled at allocation time, and the GC hasn’t run yet to clean up the objects that have become unreachable since the last sample. This is why forcing a GC (&lt;code&gt;runtime.GC()&lt;/code&gt;) before taking a heap snapshot gives you a cleaner picture.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;comparing-two-heap-snapshots-visually&quot;&gt;Comparing Two Heap Snapshots Visually&lt;/h3&gt;
&lt;p&gt;The diff view (using &lt;code&gt;-base&lt;/code&gt;) is one of the most important techniques. Here’s what to expect at each stage of a leak investigation:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stage 1: Immediately after startup&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;inuse_space top5:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     flat   cum&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   50.0MB  50.0MB  main.(*Config).load         ← config loaded into memory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   20.0MB  20.0MB  main.initRoutes             ← routing table&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    5.0MB   5.0MB  sync.(*Map).Store           ← initial cache warmup&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is your baseline. Most of this is expected startup allocation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stage 2: After 1 hour of traffic (snapshot 2)&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;inuse_space top5:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     flat   cum&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  892.0MB 892.0MB  main.(*EventStore).Append   ← WAS 0MB at startup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   50.0MB  50.0MB  main.(*Config).load         ← same as before (stable)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   20.0MB  20.0MB  main.initRoutes             ← same&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;EventStore.Append&lt;/code&gt; went from 0 to 892MB. That’s your leak.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stage 3: The diff view (heap2 - heap1)&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;go tool pprof -inuse_space -base heap1.out heap2.out&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) top5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      flat  flat%   cum   cum%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  +892.0MB 99.4%   +892.0MB 99.4%  main.(*EventStore).Append&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    +0.0MB  0.0%     +0.0MB  0.0%  main.(*Config).load         ← no change&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The diff clearly isolates the growth. Now use &lt;code&gt;list&lt;/code&gt; to find the exact line:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) list EventStore.Append&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ROUTINE ======================== main.(*EventStore).Append&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  +892.0MB  +892.0MB (flat, cum)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     15: func (s *EventStore) Append(e Event) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     16:     s.mu.Lock()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     17:     defer s.mu.Unlock()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  +892.0MB  +892.0MB     18:     s.events = append(s.events, e)  ← every call adds forever&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         .          .     19: }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Line 18 is the culprit. The &lt;code&gt;s.events&lt;/code&gt; slice grows on every request and is never trimmed. Fix: cap the slice size, use a ring buffer, or write events to an external store.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-pprof-web-ui-full-navigation-reference&quot;&gt;The pprof Web UI: Full Navigation Reference&lt;/h3&gt;
&lt;p&gt;When you open &lt;code&gt;go tool pprof -http=:8090 profile.out&lt;/code&gt;, here’s every URL and what it shows:&lt;/p&gt;













































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;URL&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;/&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Redirects to &lt;code&gt;/ui/&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;/ui/&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Default view (usually Top)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;/ui/top&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Top table — flat and cum costs&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;/ui/flamegraph&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Flame Graph — the most useful view&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;/ui/graph&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Call graph (can get cluttered)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;/ui/peek&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Callers/callees of a selected function&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;/ui/source&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Annotated source for a function&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;/ui/disasm&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Assembly-level view (for low-level work)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;/ui/weblist&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Source code in browser with cost annotations&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Keyboard shortcuts in the flame graph view:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Click a bar&lt;/strong&gt; — zoom in to that function’s subtree&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Click the root bar&lt;/strong&gt; — zoom back out&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Search box&lt;/strong&gt; — type a function name to highlight matching bars across the chart&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mouse wheel / pinch&lt;/strong&gt; — zoom in/out on the timeline axis&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;strong&gt;search box&lt;/strong&gt; is particularly useful. If you suspect &lt;code&gt;json.Marshal&lt;/code&gt; is involved across multiple call paths, typing &lt;code&gt;json&lt;/code&gt; will highlight every bar that contains the word “json” in its name — showing you all the different places JSON marshaling happens.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;continuous-profiling&quot;&gt;Continuous Profiling&lt;/h3&gt;
&lt;p&gt;The patterns above assume you collect a profile when something looks wrong. Modern teams flip this: profile &lt;em&gt;all the time&lt;/em&gt; in production at low overhead, store profiles in a time-series backend, and query them by tag, time range, or commit hash — like metrics, but for code.&lt;/p&gt;
&lt;p&gt;The major options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pyroscope&lt;/strong&gt; (open source, now part of Grafana) — works with Go’s pprof endpoints out of the box, integrates with Grafana for flame-graph queries.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Grafana Phlare&lt;/strong&gt; — Grafana Labs’ purpose-built profile storage, similar tradeoffs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Polar Signals Parca&lt;/strong&gt; — open source, eBPF-based for system-wide CPU profiling without code changes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Datadog Continuous Profiler&lt;/strong&gt; / &lt;strong&gt;Pixie&lt;/strong&gt; — commercial offerings with deeper integration.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The win: when an incident hits, you don’t need to reproduce it under a profiler — yesterday’s profile is already there. The cost: a small steady CPU/network overhead and a profile-storage tier to operate.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-decision-flowchart&quot;&gt;The Decision Flowchart&lt;/h2&gt;
&lt;p&gt;When you observe a problem, here’s how to pick the right profile:&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.6.9&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 2027 966&quot;&gt;&lt;svg class=&quot;d2-3204204872 d2-svg&quot; width=&quot;2027&quot; height=&quot;966&quot; viewBox=&quot;-25 -25 2027 966&quot;&gt;&lt;rect x=&quot;-25.000000&quot; y=&quot;-25.000000&quot; width=&quot;2027.000000&quot; height=&quot;966.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-3204204872 .text-bold {
	font-family: &quot;d2-3204204872-font-bold&quot;;
}
@font-face {
	font-family: d2-3204204872-font-bold;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-3204204872 .text-italic {
	font-family: &quot;d2-3204204872-font-italic&quot;;
}
@font-face {
	font-family: d2-3204204872-font-italic;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-3204204872 .fill-N1{fill:#0A0F25;}
		.d2-3204204872 .fill-N2{fill:#676C7E;}
		.d2-3204204872 .fill-N3{fill:#9499AB;}
		.d2-3204204872 .fill-N4{fill:#CFD2DD;}
		.d2-3204204872 .fill-N5{fill:#DEE1EB;}
		.d2-3204204872 .fill-N6{fill:#EEF1F8;}
		.d2-3204204872 .fill-N7{fill:#FFFFFF;}
		.d2-3204204872 .fill-B1{fill:#0D32B2;}
		.d2-3204204872 .fill-B2{fill:#0D32B2;}
		.d2-3204204872 .fill-B3{fill:#E3E9FD;}
		.d2-3204204872 .fill-B4{fill:#E3E9FD;}
		.d2-3204204872 .fill-B5{fill:#EDF0FD;}
		.d2-3204204872 .fill-B6{fill:#F7F8FE;}
		.d2-3204204872 .fill-AA2{fill:#4A6FF3;}
		.d2-3204204872 .fill-AA4{fill:#EDF0FD;}
		.d2-3204204872 .fill-AA5{fill:#F7F8FE;}
		.d2-3204204872 .fill-AB4{fill:#EDF0FD;}
		.d2-3204204872 .fill-AB5{fill:#F7F8FE;}
		.d2-3204204872 .stroke-N1{stroke:#0A0F25;}
		.d2-3204204872 .stroke-N2{stroke:#676C7E;}
		.d2-3204204872 .stroke-N3{stroke:#9499AB;}
		.d2-3204204872 .stroke-N4{stroke:#CFD2DD;}
		.d2-3204204872 .stroke-N5{stroke:#DEE1EB;}
		.d2-3204204872 .stroke-N6{stroke:#EEF1F8;}
		.d2-3204204872 .stroke-N7{stroke:#FFFFFF;}
		.d2-3204204872 .stroke-B1{stroke:#0D32B2;}
		.d2-3204204872 .stroke-B2{stroke:#0D32B2;}
		.d2-3204204872 .stroke-B3{stroke:#E3E9FD;}
		.d2-3204204872 .stroke-B4{stroke:#E3E9FD;}
		.d2-3204204872 .stroke-B5{stroke:#EDF0FD;}
		.d2-3204204872 .stroke-B6{stroke:#F7F8FE;}
		.d2-3204204872 .stroke-AA2{stroke:#4A6FF3;}
		.d2-3204204872 .stroke-AA4{stroke:#EDF0FD;}
		.d2-3204204872 .stroke-AA5{stroke:#F7F8FE;}
		.d2-3204204872 .stroke-AB4{stroke:#EDF0FD;}
		.d2-3204204872 .stroke-AB5{stroke:#F7F8FE;}
		.d2-3204204872 .background-color-N1{background-color:#0A0F25;}
		.d2-3204204872 .background-color-N2{background-color:#676C7E;}
		.d2-3204204872 .background-color-N3{background-color:#9499AB;}
		.d2-3204204872 .background-color-N4{background-color:#CFD2DD;}
		.d2-3204204872 .background-color-N5{background-color:#DEE1EB;}
		.d2-3204204872 .background-color-N6{background-color:#EEF1F8;}
		.d2-3204204872 .background-color-N7{background-color:#FFFFFF;}
		.d2-3204204872 .background-color-B1{background-color:#0D32B2;}
		.d2-3204204872 .background-color-B2{background-color:#0D32B2;}
		.d2-3204204872 .background-color-B3{background-color:#E3E9FD;}
		.d2-3204204872 .background-color-B4{background-color:#E3E9FD;}
		.d2-3204204872 .background-color-B5{background-color:#EDF0FD;}
		.d2-3204204872 .background-color-B6{background-color:#F7F8FE;}
		.d2-3204204872 .background-color-AA2{background-color:#4A6FF3;}
		.d2-3204204872 .background-color-AA4{background-color:#EDF0FD;}
		.d2-3204204872 .background-color-AA5{background-color:#F7F8FE;}
		.d2-3204204872 .background-color-AB4{background-color:#EDF0FD;}
		.d2-3204204872 .background-color-AB5{background-color:#F7F8FE;}
		.d2-3204204872 .color-N1{color:#0A0F25;}
		.d2-3204204872 .color-N2{color:#676C7E;}
		.d2-3204204872 .color-N3{color:#9499AB;}
		.d2-3204204872 .color-N4{color:#CFD2DD;}
		.d2-3204204872 .color-N5{color:#DEE1EB;}
		.d2-3204204872 .color-N6{color:#EEF1F8;}
		.d2-3204204872 .color-N7{color:#FFFFFF;}
		.d2-3204204872 .color-B1{color:#0D32B2;}
		.d2-3204204872 .color-B2{color:#0D32B2;}
		.d2-3204204872 .color-B3{color:#E3E9FD;}
		.d2-3204204872 .color-B4{color:#E3E9FD;}
		.d2-3204204872 .color-B5{color:#EDF0FD;}
		.d2-3204204872 .color-B6{color:#F7F8FE;}
		.d2-3204204872 .color-AA2{color:#4A6FF3;}
		.d2-3204204872 .color-AA4{color:#EDF0FD;}
		.d2-3204204872 .color-AA5{color:#F7F8FE;}
		.d2-3204204872 .color-AB4{color:#EDF0FD;}
		.d2-3204204872 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-3204204872);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-3204204872);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-3204204872);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-3204204872);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-3204204872);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-3204204872);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-3204204872);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-3204204872);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-3204204872);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-3204204872);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-3204204872);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-3204204872);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-3204204872);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-3204204872);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-3204204872);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-3204204872);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-3204204872);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-3204204872);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;QQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;ellipse rx=&quot;141.500000&quot; ry=&quot;47.000000&quot; cx=&quot;1181.500000&quot; cy=&quot;47.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;shape stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/ellipse&gt;&lt;/g&gt;&lt;text x=&quot;1181.500000&quot; y=&quot;52.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Service has a problem&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Qg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;path d=&quot;M 1182 286 C 1181 286 1180 286 1179 286 L 994 241 C 992 241 992 240 994 239 L 1179 194 C 1181 194 1184 194 1186 194 L 1370 239 C 1372 239 1372 240 1370 241 L 1185 286 C 1184 286 1183 286 1182 286 Z&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#CFD2DD&quot; class=&quot;stroke-B1 fill-N4&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;text x=&quot;1182.000000&quot; y=&quot;245.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;What are you observing?&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Qw==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;649.000000&quot; y=&quot;412.000000&quot; width=&quot;199.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;748.500000&quot; y=&quot;450.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;748.500000&quot; dy=&quot;0.000000&quot;&gt;CPU Profile&lt;/tspan&gt;&lt;tspan x=&quot;748.500000&quot; dy=&quot;18.500000&quot;&gt;collect 30s under load&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;RA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;981.000000&quot; y=&quot;412.000000&quot; width=&quot;137.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;1049.500000&quot; y=&quot;450.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;1049.500000&quot; dy=&quot;0.000000&quot;&gt;Heap Profile&lt;/tspan&gt;&lt;tspan x=&quot;1049.500000&quot; dy=&quot;18.500000&quot;&gt;-inuse_space&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;RQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;1225.000000&quot; y=&quot;412.000000&quot; width=&quot;177.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;1313.500000&quot; y=&quot;450.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;1313.500000&quot; dy=&quot;0.000000&quot;&gt;Heap Diff&lt;/tspan&gt;&lt;tspan x=&quot;1313.500000&quot; dy=&quot;18.500000&quot;&gt;-base heap1 heap2&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Rg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;path d=&quot;M 298 499 C 297 499 296 499 295 499 L 151 454 C 149 454 149 453 151 452 L 295 407 C 297 407 299 407 300 407 L 444 452 C 446 452 446 453 444 454 L 301 499 C 300 499 299 499 298 499 Z&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#CFD2DD&quot; class=&quot;stroke-B1 fill-N4&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;text x=&quot;298.000000&quot; y=&quot;458.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;What kind of slow?&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Rw==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;1476.000000&quot; y=&quot;412.000000&quot; width=&quot;162.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;1557.000000&quot; y=&quot;450.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;1557.000000&quot; dy=&quot;0.000000&quot;&gt;Goroutine Dump&lt;/tspan&gt;&lt;tspan x=&quot;1557.000000&quot; dy=&quot;18.500000&quot;&gt;?debug=2&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;SA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;1741.000000&quot; y=&quot;412.000000&quot; width=&quot;219.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;1850.500000&quot; y=&quot;450.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;1850.500000&quot; dy=&quot;0.000000&quot;&gt;Mutex Profile&lt;/tspan&gt;&lt;tspan x=&quot;1850.500000&quot; dy=&quot;18.500000&quot;&gt;SetMutexProfileFraction&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;SQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;35.000000&quot; y=&quot;628.000000&quot; width=&quot;196.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;133.000000&quot; y=&quot;666.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;133.000000&quot; dy=&quot;0.000000&quot;&gt;Execution Trace&lt;/tspan&gt;&lt;tspan x=&quot;133.000000&quot; dy=&quot;18.500000&quot;&gt;check GC STW pauses&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Sg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;368.000000&quot; y=&quot;628.000000&quot; width=&quot;188.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;462.000000&quot; y=&quot;666.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;462.000000&quot; dy=&quot;0.000000&quot;&gt;Block Profile&lt;/tspan&gt;&lt;tspan x=&quot;462.000000&quot; dy=&quot;18.500000&quot;&gt;SetBlockProfileRate&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;QzE=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;637.000000&quot; y=&quot;620.000000&quot; width=&quot;224.000000&quot; height=&quot;98.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;749.000000&quot; y=&quot;658.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;749.000000&quot; dy=&quot;0.000000&quot;&gt;top + list&lt;/tspan&gt;&lt;tspan x=&quot;749.000000&quot; dy=&quot;17.666667&quot;&gt;find wide flat functions&lt;/tspan&gt;&lt;tspan x=&quot;749.000000&quot; dy=&quot;17.666667&quot;&gt;flame graph for overview&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;RDE=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;921.000000&quot; y=&quot;628.000000&quot; width=&quot;257.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;1049.500000&quot; y=&quot;666.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;1049.500000&quot; dy=&quot;0.000000&quot;&gt;top -cum&lt;/tspan&gt;&lt;tspan x=&quot;1049.500000&quot; dy=&quot;18.500000&quot;&gt;find what holds most memory&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;RTE=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;1238.000000&quot; y=&quot;628.000000&quot; width=&quot;152.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;1314.000000&quot; y=&quot;666.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;1314.000000&quot; dy=&quot;0.000000&quot;&gt;top after diff&lt;/tspan&gt;&lt;tspan x=&quot;1314.000000&quot; dy=&quot;18.500000&quot;&gt;find what grew&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;RzE=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;1450.000000&quot; y=&quot;628.000000&quot; width=&quot;215.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;1557.500000&quot; y=&quot;666.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;1557.500000&quot; dy=&quot;0.000000&quot;&gt;look for repeated&lt;/tspan&gt;&lt;tspan x=&quot;1557.500000&quot; dy=&quot;18.500000&quot;&gt;call stacks in same state&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;SDE=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;1725.000000&quot; y=&quot;620.000000&quot; width=&quot;252.000000&quot; height=&quot;98.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;1851.000000&quot; y=&quot;658.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;1851.000000&quot; dy=&quot;0.000000&quot;&gt;top&lt;/tspan&gt;&lt;tspan x=&quot;1851.000000&quot; dy=&quot;17.666667&quot;&gt;find most contested locks&lt;/tspan&gt;&lt;tspan x=&quot;1851.000000&quot; dy=&quot;17.666667&quot;&gt;switch to RWMutex or atomic&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;STE=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;0.000000&quot; y=&quot;818.000000&quot; width=&quot;266.000000&quot; height=&quot;98.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;133.000000&quot; y=&quot;856.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;133.000000&quot; dy=&quot;0.000000&quot;&gt;MMU chart&lt;/tspan&gt;&lt;tspan x=&quot;133.000000&quot; dy=&quot;17.666667&quot;&gt;if STW is high reduce allocs&lt;/tspan&gt;&lt;tspan x=&quot;133.000000&quot; dy=&quot;17.666667&quot;&gt;use sync.Pool and GOGC tuning&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;SjE=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;326.000000&quot; y=&quot;818.000000&quot; width=&quot;272.000000&quot; height=&quot;98.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;462.000000&quot; y=&quot;856.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;462.000000&quot; dy=&quot;0.000000&quot;&gt;top&lt;/tspan&gt;&lt;tspan x=&quot;462.000000&quot; dy=&quot;17.666667&quot;&gt;find where goroutines block&lt;/tspan&gt;&lt;tspan x=&quot;462.000000&quot; dy=&quot;17.666667&quot;&gt;check DB pool size and timeouts&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgQilbMF0=&quot;&gt;&lt;marker id=&quot;mk-d2-3204204872-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 1181.980000 95.999900 C 1181.599976 134.000000 1181.599976 154.000000 1181.960000 190.000200&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3204204872-3488378134)&quot; mask=&quot;url(#d2-3204204872)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgQylbMF0=&quot;&gt;&lt;path d=&quot;M 1083.058953 263.482014 C 816.000000 329.799988 748.750000 359.700012 748.750000 408.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3204204872-3488378134)&quot; mask=&quot;url(#d2-3204204872)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;889.500000&quot; y=&quot;317.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;High CPU usage&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgRClbMF0=&quot;&gt;&lt;path d=&quot;M 1134.447909 277.261353 C 1066.599976 332.399994 1049.250000 359.700012 1049.250000 408.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3204204872-3488378134)&quot; mask=&quot;url(#d2-3204204872)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;1068.500000&quot; y=&quot;337.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;High memory / OOM&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgRSlbMF0=&quot;&gt;&lt;path d=&quot;M 1228.552091 277.261353 C 1296.400024 332.399994 1313.750000 359.700012 1313.750000 408.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3204204872-3488378134)&quot; mask=&quot;url(#d2-3204204872)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;1294.500000&quot; y=&quot;337.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Memory growing over time&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgRilbMF0=&quot;&gt;&lt;path d=&quot;M 1051.014509 255.240467 C 448.600006 328.200012 297.600006 358.600006 297.966944 403.000137&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3204204872-3488378134)&quot; mask=&quot;url(#d2-3204204872)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;650.500000&quot; y=&quot;309.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Slow but CPU is LOW&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgRylbMF0=&quot;&gt;&lt;path d=&quot;M 1273.923048 265.549442 C 1500.199951 330.200012 1557.250000 359.700012 1557.250000 408.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3204204872-3488378134)&quot; mask=&quot;url(#d2-3204204872)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;1442.500000&quot; y=&quot;319.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Goroutine count growing&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgSClbMF0=&quot;&gt;&lt;path d=&quot;M 1299.974848 258.316190 C 1740.199951 328.799988 1850.750000 359.700012 1850.750000 408.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3204204872-3488378134)&quot; mask=&quot;url(#d2-3204204872)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;1602.000000&quot; y=&quot;312.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Does not scale with CPUs&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEYgLSZndDsgSSlbMF0=&quot;&gt;&lt;path d=&quot;M 246.328113 485.097631 C 156.000000 544.400024 133.000000 573.299988 133.000000 624.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3204204872-3488378134)&quot; mask=&quot;url(#d2-3204204872)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;163.500000&quot; y=&quot;545.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Random latency spikes&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEYgLSZndDsgSilbMF0=&quot;&gt;&lt;path d=&quot;M 348.671887 485.097631 C 439.000000 544.400024 462.000000 573.299988 462.000000 624.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3204204872-3488378134)&quot; mask=&quot;url(#d2-3204204872)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;432.000000&quot; y=&quot;545.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Consistent slowness&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEMgLSZndDsgQzEpWzBd&quot;&gt;&lt;path d=&quot;M 748.750000 495.500000 C 748.750000 546.299988 748.750000 571.700012 748.750000 616.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3204204872-3488378134)&quot; mask=&quot;url(#d2-3204204872)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEQgLSZndDsgRDEpWzBd&quot;&gt;&lt;path d=&quot;M 1049.250000 495.500000 C 1049.250000 546.299988 1049.250000 573.299988 1049.250000 624.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3204204872-3488378134)&quot; mask=&quot;url(#d2-3204204872)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEUgLSZndDsgRTEpWzBd&quot;&gt;&lt;path d=&quot;M 1313.750000 495.500000 C 1313.750000 546.299988 1313.750000 573.299988 1313.750000 624.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3204204872-3488378134)&quot; mask=&quot;url(#d2-3204204872)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEcgLSZndDsgRzEpWzBd&quot;&gt;&lt;path d=&quot;M 1557.250000 495.500000 C 1557.250000 546.299988 1557.250000 573.299988 1557.250000 624.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3204204872-3488378134)&quot; mask=&quot;url(#d2-3204204872)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEggLSZndDsgSDEpWzBd&quot;&gt;&lt;path d=&quot;M 1850.750000 495.500000 C 1850.750000 546.299988 1850.750000 571.700012 1850.750000 616.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3204204872-3488378134)&quot; mask=&quot;url(#d2-3204204872)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEkgLSZndDsgSTEpWzBd&quot;&gt;&lt;path d=&quot;M 133.000000 712.000000 C 133.000000 756.400024 133.000000 778.000000 133.000000 814.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3204204872-3488378134)&quot; mask=&quot;url(#d2-3204204872)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEogLSZndDsgSjEpWzBd&quot;&gt;&lt;path d=&quot;M 462.000000 712.000000 C 462.000000 756.400024 462.000000 778.000000 462.000000 814.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3204204872-3488378134)&quot; mask=&quot;url(#d2-3204204872)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;mask id=&quot;d2-3204204872&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;2027&quot; height=&quot;966&quot;&gt;
&lt;rect x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;2027&quot; height=&quot;966&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;1104.000000&quot; y=&quot;36.500000&quot; width=&quot;155&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;1095.000000&quot; y=&quot;229.500000&quot; width=&quot;174&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;671.500000&quot; y=&quot;434.500000&quot; width=&quot;154&quot; height=&quot;37&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;1003.500000&quot; y=&quot;434.500000&quot; width=&quot;92&quot; height=&quot;37&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;1247.500000&quot; y=&quot;434.500000&quot; width=&quot;132&quot; height=&quot;37&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;231.500000&quot; y=&quot;442.500000&quot; width=&quot;133&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;1498.500000&quot; y=&quot;434.500000&quot; width=&quot;117&quot; height=&quot;37&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;1763.500000&quot; y=&quot;434.500000&quot; width=&quot;174&quot; height=&quot;37&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;57.500000&quot; y=&quot;650.500000&quot; width=&quot;151&quot; height=&quot;37&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;390.500000&quot; y=&quot;650.500000&quot; width=&quot;143&quot; height=&quot;37&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;659.500000&quot; y=&quot;642.500000&quot; width=&quot;179&quot; height=&quot;53&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;943.500000&quot; y=&quot;650.500000&quot; width=&quot;212&quot; height=&quot;37&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;1260.500000&quot; y=&quot;650.500000&quot; width=&quot;107&quot; height=&quot;37&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;1472.500000&quot; y=&quot;650.500000&quot; width=&quot;170&quot; height=&quot;37&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;1747.500000&quot; y=&quot;642.500000&quot; width=&quot;207&quot; height=&quot;53&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;22.500000&quot; y=&quot;840.500000&quot; width=&quot;221&quot; height=&quot;53&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;348.500000&quot; y=&quot;840.500000&quot; width=&quot;227&quot; height=&quot;53&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;837.000000&quot; y=&quot;301.000000&quot; width=&quot;105&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;1002.000000&quot; y=&quot;321.000000&quot; width=&quot;133&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;1207.000000&quot; y=&quot;321.000000&quot; width=&quot;175&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;583.000000&quot; y=&quot;293.000000&quot; width=&quot;135&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;1361.000000&quot; y=&quot;303.000000&quot; width=&quot;163&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;1520.000000&quot; y=&quot;296.000000&quot; width=&quot;164&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;88.000000&quot; y=&quot;529.000000&quot; width=&quot;151&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;366.000000&quot; y=&quot;529.000000&quot; width=&quot;132&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;hr&gt;
&lt;h2 id=&quot;optimization-techniques-reference&quot;&gt;Optimization Techniques Reference&lt;/h2&gt;
&lt;p&gt;Once you’ve found a bottleneck, here are the most common fixes organized by category.&lt;/p&gt;
&lt;h3 id=&quot;reducing-allocations&quot;&gt;Reducing Allocations&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Use &lt;code&gt;strings.Builder&lt;/code&gt; instead of &lt;code&gt;+&lt;/code&gt; concatenation:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Bad: each + creates a new string (O(n²) total allocations)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;result &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; _, s &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; parts {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    result &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;+=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; s &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;, &quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Good: Builder amortizes allocations&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; b &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;strings&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Builder&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;b.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Grow&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(estimatedSize) &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// optional: pre-allocate if you know the size&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; i, s &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; parts {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    b.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;WriteString&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(s)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; len&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(parts)&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        b.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;WriteString&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;, &quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;result &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; b.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Pre-allocate slices:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Bad: append keeps reallocating the backing array&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; users []&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; _, row &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; rows {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    users &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; append&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(users, &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;scanUser&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(row))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Good: allocate once if you know the count&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;users &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; make&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;([]&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;len&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(rows)) &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// capacity = len(rows)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; _, row &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; rows {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    users &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; append&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(users, &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;scanUser&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(row))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Use &lt;code&gt;sync.Pool&lt;/code&gt; for hot paths:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; jsonEncoderPool &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; sync&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Pool&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    New: &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;any&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; json.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;NewEncoder&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(io.Discard) &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// placeholder writer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// In the actual handler, we need a new encoder (can&apos;t reuse across different writers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// But we CAN pool the underlying buffer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; bufPool &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; sync&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Pool&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    New: &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;any&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;bytes&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Buffer&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Avoid interface boxing for simple values:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Bad: creates an interface value (allocation if value doesn&apos;t fit in pointer)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;interface&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{} &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 42&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;fmt.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Println&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(x)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Good for hot paths: use concrete types&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; processInt&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) { fmt.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Println&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(x) }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;reducing-lock-contention&quot;&gt;Reducing Lock Contention&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Prefer &lt;code&gt;sync.RWMutex&lt;/code&gt; for read-heavy maps:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Use RLock for reads (multiple goroutines can hold RLock simultaneously)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Use Lock only for writes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Use &lt;code&gt;sync/atomic&lt;/code&gt; for counters and flags:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; requestCount &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;int64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;atomic.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;AddInt64&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;requestCount, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Consider &lt;code&gt;sync.Map&lt;/code&gt; for read-heavy, write-rarely maps:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// sync.Map is optimized for the case where entries are written once&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// and read many times, or when different goroutines access disjoint keys&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; cache &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sync&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Map&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;cache.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Store&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, value)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;v, ok &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; cache.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Load&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;reducing-gc-pressure&quot;&gt;Reducing GC Pressure&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Tune GOGC via environment:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Default is GOGC=100 (GC when heap doubles from last collection size)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Higher = less frequent GC, more memory usage&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;GOGC&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;200&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; ./myservice&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Set a hard memory limit (Go 1.19+)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# The runtime will run GC more aggressively if approaching this limit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;GOMEMLIMIT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;500MiB&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; ./myservice&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Avoid closures that capture large values:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Bad: closure captures entire largeConfig (keeps it alive)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; makeHandler&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;largeConfig&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Config&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;HandlerFunc&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; func&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;w&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; http&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;ResponseWriter&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Request&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;        // uses only largeConfig.Timeout&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;        doWork&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(largeConfig.Timeout)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Good: capture only what you need&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; makeHandler&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;largeConfig&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Config&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;HandlerFunc&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    timeout &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; largeConfig.Timeout  &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;// only this escapes to the heap&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; func&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;w&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; http&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;ResponseWriter&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Request&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;        doWork&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(timeout)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;quick-reference&quot;&gt;Quick Reference&lt;/h2&gt;
&lt;h3 id=&quot;collecting-profiles&quot;&gt;Collecting Profiles&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# CPU — 30 second sample (adjust ?seconds=N as needed)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; http://localhost:6060/debug/pprof/profile?seconds=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;30&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Heap — live objects right now&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -inuse_space&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; http://localhost:6060/debug/pprof/heap&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Heap — everything allocated since start (for GC pressure)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -alloc_space&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; http://localhost:6060/debug/pprof/heap&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Heap diff — what grew between two snapshots&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap1.out&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; http://localhost:6060/debug/pprof/heap&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# ... wait ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap2.out&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; http://localhost:6060/debug/pprof/heap&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -inuse_space&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -base&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap1.out&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; heap2.out&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Goroutine dump — full stacks of every goroutine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;http://localhost:6060/debug/pprof/goroutine?debug=2&quot;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; goroutines.txt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Mutex contention (requires SetMutexProfileFraction)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; http://localhost:6060/debug/pprof/mutex&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Block profile (requires SetBlockProfileRate)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; http://localhost:6060/debug/pprof/block&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Execution trace&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; trace.out&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;http://localhost:6060/debug/pprof/trace?seconds=5&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; trace&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; trace.out&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Benchmark profiles&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; test&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -bench=BenchmarkMyFunc&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -benchmem&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -cpuprofile=cpu.out&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -memprofile=mem.out&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; ./...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;interactive-pprof-commands&quot;&gt;Interactive pprof Commands&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) top10              # top 10 by flat time (CPU) or flat size (heap)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) top10 -cum         # top 10 by cumulative time/size&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) list FunctionName  # annotated source with per-line costs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) web                # call graph in browser&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) weblist FuncName   # annotated source in browser&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) tree               # call tree rooted at top nodes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) png                # save call graph as PNG&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) svg                # save call graph as SVG&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(pprof) help               # list all commands&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;opening-the-web-ui-flame-graph&quot;&gt;Opening the Web UI (Flame Graph)&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# From a saved file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -http=:8090&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; cpu.out&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Directly from a live service&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pprof&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -http=:8090&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; http://localhost:6060/debug/pprof/profile?seconds=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;30&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;a-note-on-profiling-in-production&quot;&gt;A Note on Profiling in Production&lt;/h2&gt;
&lt;p&gt;Running profiling in production is safe and common. The key points:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;CPU profiling&lt;/strong&gt; at the default 100Hz sampling rate adds about 1-5% overhead. This is acceptable for most services.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Heap profiling&lt;/strong&gt; is always on by default (you just need to fetch the snapshot). No meaningful overhead.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Goroutine dumps&lt;/strong&gt; are cheap to collect but the goroutine dump itself stops the world briefly — on a service with 100,000 goroutines, this could take tens of milliseconds. Don’t collect these in a tight loop.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mutex and block profiling&lt;/strong&gt; at high sampling rates have measurable overhead. Use conservative rates in production (&lt;code&gt;SetMutexProfileFraction(5)&lt;/code&gt;, &lt;code&gt;SetBlockProfileRate(1000000)&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Traces&lt;/strong&gt; have the highest overhead. Collect only for short intervals (5s) and only when investigating an active issue.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Never expose &lt;code&gt;/debug/pprof/&lt;/code&gt; publicly.&lt;/strong&gt; Bind the debug server to &lt;code&gt;localhost&lt;/code&gt; and use SSH port forwarding or an internal VPN to access it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The habit to build is this: when something is slow or using too much memory, profile before you optimize. Look at the data before you change the code. The 20 minutes spent profiling will almost always save you hours of guessing and reverting.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;The more you use these tools, the faster you get. Eventually profiling becomes a reflex — the first thing you reach for, not the last.&lt;/p&gt;</content:encoded></item><item><title>PostgreSQL EXPLAIN: Reading and Understanding Query Plans</title><link>https://abhimanyunagurkar.com/blog/postgres-explain/</link><guid isPermaLink="true">https://abhimanyunagurkar.com/blog/postgres-explain/</guid><description>How to read PostgreSQL EXPLAIN output: scan types, join algorithms, and the cost model — turn opaque query plans into actionable insights.</description><pubDate>Tue, 21 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When a query is slow, your first move should always be &lt;code&gt;EXPLAIN&lt;/code&gt;. Most developers have seen the output, stared at it briefly, and moved on without really understanding what they were looking at. This post changes that. We’ll go from zero to being able to read a plan with confidence — including the gotchas that routinely fool even experienced engineers.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;what-explain-actually-does&quot;&gt;What EXPLAIN Actually Does&lt;/h2&gt;
&lt;p&gt;When you submit a SQL query, PostgreSQL doesn’t execute it immediately. First, the &lt;strong&gt;query planner&lt;/strong&gt; analyzes all the ways it could satisfy the query and estimates which is cheapest. &lt;code&gt;EXPLAIN&lt;/code&gt; shows you the plan the planner chose, without actually running the query.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;EXPLAIN ANALYZE&lt;/code&gt; runs the query &lt;em&gt;and&lt;/em&gt; shows you the plan alongside the actual measured times. That distinction matters enormously, as we’ll see.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Shows the plan only (no execution)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;EXPLAIN &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; user_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 42&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Runs the query and shows plan + actual timings&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;EXPLAIN ANALYZE &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; user_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 42&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Most useful form: adds buffers (I/O stats) and verbose node info&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;EXPLAIN (ANALYZE, BUFFERS, FORMAT &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;TEXT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; user_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 42&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The planner’s estimates are based on &lt;strong&gt;statistics&lt;/strong&gt; — table row counts, column value distributions, and correlation info stored in &lt;code&gt;pg_statistic&lt;/code&gt; (surfaced via &lt;code&gt;pg_stats&lt;/code&gt;). If your statistics are stale (last &lt;code&gt;ANALYZE&lt;/code&gt; ran a while ago), the planner will make poor decisions.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;reading-the-plan-tree&quot;&gt;Reading the Plan Tree&lt;/h2&gt;
&lt;p&gt;A query plan is a &lt;strong&gt;tree of nodes&lt;/strong&gt;. Each node is an operation — a scan, a join, a sort, an aggregate. The tree is read &lt;strong&gt;bottom-up&lt;/strong&gt;: leaves execute first, results flow upward to parent nodes.&lt;/p&gt;
&lt;p&gt;Here’s a simple plan to orient us:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Nested Loop  (cost=0.43..16.50 rows=10 width=64)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  -&gt;  Index Scan using users_pkey on users  (cost=0.43..8.45 rows=1 width=32)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        Index Cond: (id = 42)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  -&gt;  Seq Scan on orders  (cost=0.00..8.00 rows=10 width=32)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        Filter: (user_id = 42)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;How to read this:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The bottom-most nodes (&lt;code&gt;Index Scan&lt;/code&gt; on users, &lt;code&gt;Seq Scan&lt;/code&gt; on orders) run first.&lt;/li&gt;
&lt;li&gt;Their results feed up into &lt;code&gt;Nested Loop&lt;/code&gt;, which joins them.&lt;/li&gt;
&lt;li&gt;Indentation = depth in the tree. More indented = runs earlier.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;the-cost-fields&quot;&gt;The Cost Fields&lt;/h3&gt;
&lt;p&gt;Every node shows &lt;code&gt;(cost=startup..total rows=N width=W)&lt;/code&gt;:&lt;/p&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Meaning&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;startup&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Cost before the first row can be returned (e.g. building a sort buffer)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;total&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Estimated total cost if all rows are consumed&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;rows&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Estimated number of rows this node will output&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;width&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Estimated average row size in bytes&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Cost is unitless&lt;/strong&gt; — it’s in abstract “cost units” that PostgreSQL uses internally to compare options. A cost of 1.0 roughly corresponds to one sequential page read. It’s meaningless as an absolute number but useful for comparing nodes within the same plan.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;total&lt;/code&gt; cost of the root node is what the planner minimized when choosing this plan. Higher cost = planner thinks it’s more expensive.&lt;/p&gt;
&lt;h3 id=&quot;explain-analyze-adds-actual-timings&quot;&gt;EXPLAIN ANALYZE adds actual timings&lt;/h3&gt;
&lt;p&gt;With &lt;code&gt;ANALYZE&lt;/code&gt;, each node also shows:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Seq Scan on orders  (cost=0.00..8820.00 rows=200000 width=40)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    (actual time=0.012..412.340 rows=198234 loops=1)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(actual time=startup..total rows=N loops=N)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Meaning&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;actual time&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Real measured time in milliseconds (startup..total)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;actual rows&lt;/code&gt;&lt;/td&gt;&lt;td&gt;How many rows were actually produced&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;loops&lt;/code&gt;&lt;/td&gt;&lt;td&gt;How many times this node executed (important in joins!)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;The &lt;code&gt;loops&lt;/code&gt; field is critical.&lt;/strong&gt; In a nested loop join, the inner side runs once per row from the outer side. If &lt;code&gt;loops=500&lt;/code&gt; and &lt;code&gt;actual time=0.05..0.10&lt;/code&gt;, the total contribution of that node is &lt;code&gt;0.10ms × 500 = 50ms&lt;/code&gt; — not 0.10ms. PostgreSQL reports per-loop averages, so you must multiply by &lt;code&gt;loops&lt;/code&gt; yourself.&lt;/p&gt;
&lt;h3 id=&quot;buffers-shows-io&quot;&gt;BUFFERS shows I/O&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;EXPLAIN (ANALYZE, BUFFERS)&lt;/code&gt; adds buffer hit/miss stats to each node:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Seq Scan on orders  (cost=0.00..8820.00 rows=200000 width=40)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    (actual time=0.012..412.340 rows=198234 loops=1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Buffers: shared hit=1240 read=6780&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Meaning&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;shared hit&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Pages found in PostgreSQL’s shared buffer cache (fast)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;shared read&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Pages read from disk or OS page cache (slow)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;shared written&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Dirty pages written during the query&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;temp read/written&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Temporary disk I/O (spilled sorts, hash joins)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;High &lt;code&gt;read&lt;/code&gt; vs &lt;code&gt;hit&lt;/code&gt; ratio = your working set doesn’t fit in &lt;code&gt;shared_buffers&lt;/code&gt;. High &lt;code&gt;temp written&lt;/code&gt; = your sort/hash operations don’t fit in &lt;code&gt;work_mem&lt;/code&gt; (the per-operation memory budget for sorts, hashes, and bitmap allocations — defaults to 4 MB) and are spilling to disk.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-full-explain-output--annotated&quot;&gt;The Full EXPLAIN Output — Annotated&lt;/h2&gt;
&lt;p&gt;Let’s look at a realistic plan with &lt;code&gt;ANALYZE&lt;/code&gt;, &lt;code&gt;BUFFERS&lt;/code&gt;, and &lt;code&gt;FORMAT TEXT&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;EXPLAIN (ANALYZE, BUFFERS, FORMAT &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;TEXT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; u&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;COUNT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;o&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; order_count&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; users u&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;JOIN&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders o &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ON&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; o&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;user_id&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; u&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;id&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; u&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;created_at&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;2025-01-01&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;GROUP BY&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; u&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;u&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ORDER BY&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; order_count &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;DESC&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;LIMIT&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Limit  (cost=18420.32..18420.34 rows=10 width=40)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       (actual time=523.812..523.814 rows=10 loops=1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  -&gt;  Sort  (cost=18420.32..18445.32 rows=10000 width=40)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            (actual time=523.811..523.812 rows=10 loops=1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        Sort Key: (count(o.id)) DESC&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        Sort Method: top-N heapsort  Memory: 25kB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        -&gt;  HashAggregate  (cost=18000.00..18100.00 rows=10000 width=40)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                           (actual time=519.234..521.456 rows=9823 loops=1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              Group Key: u.id, u.name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              Batches: 1  Memory Usage: 2048kB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              -&gt;  Hash Join  (cost=1240.00..16500.00 rows=100000 width=16)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                             (actual time=8.432..480.231 rows=98432 loops=1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    Hash Cond: (o.user_id = u.id)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    Buffers: shared hit=4820 read=2340&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    -&gt;  Seq Scan on orders o  (cost=0.00..8820.00 rows=200000 width=8)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                                              (actual time=0.012..210.340 rows=200000 loops=1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                          Buffers: shared hit=2240 read=2340&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    -&gt;  Hash  (cost=980.00..980.00 rows=20800 width=16)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                               (actual time=8.120..8.120 rows=20812 loops=1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                          Buckets: 32768  Batches: 1  Memory Usage: 1280kB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                          -&gt;  Index Scan using users_created_at_idx on users u&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                                (cost=0.43..980.00 rows=20800 width=16)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                                (actual time=0.032..6.234 rows=20812 loops=1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                              Index Cond: (created_at &gt; &apos;2025-01-01&apos;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                              Buffers: shared hit=580&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Reading this bottom-up:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Index Scan on users&lt;/code&gt;&lt;/strong&gt; — uses the &lt;code&gt;created_at&lt;/code&gt; index to find the 20,812 users created after 2025-01-01. Fast, 6ms.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Hash&lt;/code&gt;&lt;/strong&gt; — builds a hash table from those users in memory (1280kB). One-time cost.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Seq Scan on orders&lt;/code&gt;&lt;/strong&gt; — reads all 200,000 orders. The bottleneck: 210ms, 2340 pages read from disk.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Hash Join&lt;/code&gt;&lt;/strong&gt; — probes the hash table with each order row to find matches. Total 480ms.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;HashAggregate&lt;/code&gt;&lt;/strong&gt; — groups and counts. 519ms cumulative.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Sort&lt;/code&gt;&lt;/strong&gt; — sorts by count descending using a top-N heapsort (only keeps 10 rows, very cheap).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Limit&lt;/code&gt;&lt;/strong&gt; — returns the top 10 rows.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The problem is obvious: the &lt;code&gt;Seq Scan on orders&lt;/code&gt; with 2340 disk reads is the bottleneck. An index on &lt;code&gt;orders.user_id&lt;/code&gt; would change this to an index scan, potentially eliminating most of those reads.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;seq-scan-vs-index-scan-vs-bitmap-index-scan&quot;&gt;Seq Scan vs Index Scan vs Bitmap Index Scan&lt;/h2&gt;
&lt;p&gt;This is the section most engineers want to understand. PostgreSQL has three fundamentally different ways to read rows from a table, each with different trade-offs.&lt;/p&gt;
&lt;h3 id=&quot;sequential-scan-seq-scan&quot;&gt;Sequential Scan (Seq Scan)&lt;/h3&gt;
&lt;p&gt;Reads every page of the table from start to finish, in physical disk order.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Seq Scan on orders  (cost=0.00..8820.00 rows=200000 width=40)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    (actual time=0.012..412.340 rows=198234 loops=1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Filter: (status = &apos;pending&apos;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Rows Removed by Filter: 1766&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;When PostgreSQL chooses it:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No usable index exists.&lt;/li&gt;
&lt;li&gt;The query will return a large fraction of the table (typically &gt;5-20% of rows). Reading the index + jumping around the heap for each row costs &lt;em&gt;more&lt;/em&gt; than just reading the whole table sequentially.&lt;/li&gt;
&lt;li&gt;The table is small — a seq scan on a 50-row table is always faster than any index lookup.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;random_page_cost&lt;/code&gt; is set high (spinning disks) making index random I/O expensive relative to sequential I/O.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;The key insight:&lt;/strong&gt; Seq scan has low overhead per page. Index scan has high overhead per row (random I/O). The crossover point is usually around 5-15% of the table’s rows depending on your storage and &lt;code&gt;random_page_cost&lt;/code&gt; setting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When it surprises you:&lt;/strong&gt; You added an index but the planner still chooses a seq scan. This usually means either (a) you’re fetching more rows than you think, (b) your statistics are stale (&lt;code&gt;ANALYZE&lt;/code&gt; needed), or (c) &lt;code&gt;random_page_cost&lt;/code&gt; is too high for SSD storage (default is 4.0, should be ~1.1 on SSD).&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Check what fraction of rows your filter selects&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; COUNT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FILTER&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;pending&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; COUNT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;AS&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pct&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- If pct &gt; 10%, seq scan is probably right&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;index-scan&quot;&gt;Index Scan&lt;/h3&gt;
&lt;p&gt;Uses a B-tree (or other) index to find row locations, then fetches each row from the heap (the main table storage) one by one.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Index Scan using orders_user_id_idx on orders&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  (cost=0.43..42.50 rows=10 width=40)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  (actual time=0.032..0.218 rows=8 loops=1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Index Cond: (user_id = 42)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;How it works:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Traverse the B-tree index to find all entries matching &lt;code&gt;user_id = 42&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For each index entry, follow the heap pointer to fetch the actual row from the table — these are TIDs (tuple identifiers — the &lt;code&gt;(page, slot)&lt;/code&gt; physical addresses we covered in &lt;a href=&quot;/blog/db-storage-and-indexing/&quot;&gt;How Databases Actually Store and Find Your Data&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Each heap fetch is a &lt;strong&gt;random I/O&lt;/strong&gt; — potentially a different page each time.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;When PostgreSQL chooses Index Scan:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A small fraction of rows match the predicate (low selectivity in the result-set sense).&lt;/li&gt;
&lt;li&gt;The index columns and the &lt;em&gt;physical row order&lt;/em&gt; are well-correlated — i.e. nearby keys in the index map to nearby pages on disk. Postgres tracks this via &lt;code&gt;pg_stats.correlation&lt;/code&gt; (1.0 = perfect, 0.0 = random). High correlation makes Index Scan cheap because heap fetches stay sequential.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When correlation is low, Postgres prefers &lt;strong&gt;Bitmap Index Scan&lt;/strong&gt; instead — same index, but it sorts the matching tuple IDs by physical page before fetching, turning random heap I/O into a sequential pass.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Check correlation for a column&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; tablename, attname, correlation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pg_stats&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; tablename &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;orders&apos;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; attname &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;user_id&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Index-only scan&lt;/strong&gt; — a variant where the index contains all the columns the query needs. PostgreSQL can return results without ever touching the heap:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Index Only Scan using orders_user_status_idx on orders&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  (cost=0.43..12.50 rows=10 width=8)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  (actual time=0.018..0.045 rows=8 loops=1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Index Cond: (user_id = 42)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Heap Fetches: 0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Heap Fetches: 0&lt;/code&gt; means pure index reads. This is the fastest possible scan for selective queries. Requires that all &lt;code&gt;SELECT&lt;/code&gt;ed columns (and the &lt;code&gt;WHERE&lt;/code&gt; columns) are in the index. PostgreSQL also needs the &lt;code&gt;visibility map&lt;/code&gt; (a per-table bitmap that tracks which pages contain only tuples visible to all transactions — see &lt;a href=&quot;/blog/postgres-indexing/&quot;&gt;PostgreSQL Indexing Deep Dive&lt;/a&gt; for the mechanics) to confirm rows are visible (otherwise it must fetch from the heap), so &lt;code&gt;VACUUM&lt;/code&gt; must have run recently.&lt;/p&gt;
&lt;h3 id=&quot;bitmap-index-scan&quot;&gt;Bitmap Index Scan&lt;/h3&gt;
&lt;p&gt;Bitmap Index Scan is PostgreSQL’s most clever scan strategy — a two-phase approach designed specifically for the middle-ground situation where too many rows match for an index scan, but not enough to justify reading the entire table. It trades an extra bookkeeping step for much cheaper I/O.&lt;/p&gt;
&lt;h4 id=&quot;the-two-phases-in-detail&quot;&gt;The Two Phases in Detail&lt;/h4&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Bitmap Heap Scan on orders  (cost=240.32..4820.10 rows=12000 width=40)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                             (actual time=4.231..82.340 rows=11984 loops=1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Recheck Cond: (status = &apos;pending&apos;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Heap Blocks: exact=3420&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  -&gt;  Bitmap Index Scan on orders_status_idx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        (cost=0.00..237.32 rows=12000 width=0)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        (actual time=3.890..3.890 rows=11984 loops=1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        Index Cond: (status = &apos;pending&apos;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Phase 1 — Bitmap Index Scan:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;PostgreSQL walks the index (just like a regular index scan) and collects the physical address (TID — tuple identifier) of every row matching the condition. But instead of immediately fetching those rows from the heap, it builds a &lt;strong&gt;bitmap&lt;/strong&gt; in memory. Each bit in the bitmap represents one heap page. If any matching row lives on a page, that page’s bit is set to 1.&lt;/p&gt;
&lt;p&gt;At the end of Phase 1, we know &lt;em&gt;which pages&lt;/em&gt; contain matching rows — but we haven’t touched the heap at all yet. Crucially, if 50 matching rows all happen to live on page 4820, that page’s bit is set exactly once, not 50 times.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 2 — Bitmap Heap Scan:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;PostgreSQL scans the heap, but only reads pages whose bit is set. Because it processes pages in ascending physical page order (not in the random order the index would produce), this is &lt;strong&gt;sequential I/O&lt;/strong&gt; — the OS and storage layer can prefetch ahead efficiently. Each flagged page is read once, all matching rows on that page are extracted, and the &lt;code&gt;Recheck Cond&lt;/code&gt; filter is applied.&lt;/p&gt;
&lt;h4 id=&quot;why-this-is-faster-than-index-scan-at-medium-selectivity&quot;&gt;Why This Is Faster Than Index Scan at Medium Selectivity&lt;/h4&gt;
&lt;p&gt;If 50,000 rows match a predicate over a 1M-row table on 10K pages, an Index Scan can hit up to ~10K distinct pages in &lt;em&gt;index order&lt;/em&gt;, which on a poorly-correlated index means thousands of random I/Os. A Bitmap Index Scan first builds a bitmap of matching row IDs, sorts them by physical page, and reads each page once — turning thousands of random reads into ~10K sequential ones.&lt;/p&gt;
&lt;p&gt;The bitmap converts random I/O into sequential I/O by batching and sorting all the access locations first.&lt;/p&gt;
&lt;h4 id=&quot;exact-vs-lossy-bitmaps&quot;&gt;Exact vs Lossy Bitmaps&lt;/h4&gt;
&lt;p&gt;The bitmap lives in memory — specifically in &lt;code&gt;work_mem&lt;/code&gt;. This is where PostgreSQL’s adaptiveness becomes especially interesting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When there’s enough &lt;code&gt;work_mem&lt;/code&gt;:&lt;/strong&gt; The bitmap tracks individual rows within each page (bit-per-tuple). This is an &lt;strong&gt;exact&lt;/strong&gt; bitmap. When the heap scan reads a page, it knows exactly which rows to return — no extra filtering needed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When &lt;code&gt;work_mem&lt;/code&gt; is exhausted:&lt;/strong&gt; PostgreSQL degrades the bitmap from per-tuple to per-page resolution. Each bit now means “this page &lt;em&gt;might&lt;/em&gt; have a matching row.” This is a &lt;strong&gt;lossy&lt;/strong&gt; bitmap. To compensate, the &lt;code&gt;Recheck Cond&lt;/code&gt; filter is applied to every row on every flagged page to discard false positives. The query still produces correct results, but more heap rows are fetched and filtered.&lt;/p&gt;
&lt;p&gt;You can see this distinction in the plan output:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Bitmap Heap Scan on orders&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Recheck Cond: (status = &apos;pending&apos;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Heap Blocks: exact=3200 lossy=820    -- 820 pages went lossy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Rows Removed by Index Recheck: 14200 -- extra rows fetched and discarded&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;lossy=820&lt;/code&gt; means 820 pages were read without knowing exactly which rows were valid — all rows on those pages had to be rechecked. If &lt;code&gt;lossy&lt;/code&gt; is large relative to &lt;code&gt;exact&lt;/code&gt;, you’re reading significantly more heap data than necessary. &lt;strong&gt;Fix: increase &lt;code&gt;work_mem&lt;/code&gt;&lt;/strong&gt; for the session or globally.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Test the effect&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; work_mem &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;64MB&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;EXPLAIN (ANALYZE, BUFFERS) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ...;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- If &apos;lossy&apos; drops to 0, you&apos;ve found your sweet spot&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;bitmapand--using-multiple-indexes-simultaneously&quot;&gt;BitmapAnd — Using Multiple Indexes Simultaneously&lt;/h4&gt;
&lt;p&gt;This is one of the most powerful capabilities of the bitmap approach. When a query has AND conditions on multiple indexed columns, PostgreSQL can build a separate bitmap for each index and intersect them:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Bitmap Heap Scan on orders  (cost=340.15..2840.10 rows=500 width=40)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                             (actual time=5.230..18.420 rows=487 loops=1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Recheck Cond: ((user_id = 42) AND (status = &apos;pending&apos;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Heap Blocks: exact=420&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  -&gt;  BitmapAnd  (cost=340.15..340.15 rows=500 width=0)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                  (actual time=5.100..5.100 rows=0 loops=1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        -&gt;  Bitmap Index Scan on orders_user_id_idx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              (cost=0.00..120.43 rows=5000 width=0)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              (actual time=1.230..1.230 rows=4823 loops=1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              Index Cond: (user_id = 42)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        -&gt;  Bitmap Index Scan on orders_status_idx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              (cost=0.00..218.97 rows=50000 width=0)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              (actual time=3.120..3.120 rows=49320 loops=1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              Index Cond: (status = &apos;pending&apos;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;How BitmapAnd works:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Walk &lt;code&gt;orders_user_id_idx&lt;/code&gt; → bitmap A (pages containing user 42’s orders, 5000 rows → maybe 200 pages set).&lt;/li&gt;
&lt;li&gt;Walk &lt;code&gt;orders_status_idx&lt;/code&gt; → bitmap B (pages containing pending orders, 50000 rows → maybe 2000 pages set).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AND the two bitmaps&lt;/strong&gt; (bitwise AND) → result bitmap has only pages that appear in both. From 2200 candidate pages, only ~420 pages actually contain rows matching both conditions.&lt;/li&gt;
&lt;li&gt;Read those 420 pages sequentially.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Without a composite index, this is the next best thing — two mediocre single-column indexes combine to behave almost like a targeted composite index. The AND step is O(pages/64) — extremely cheap, just a bitwise AND across machine words.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When BitmapAnd is chosen over a composite index:&lt;/strong&gt; If you have a composite index &lt;code&gt;(user_id, status)&lt;/code&gt;, the planner will usually prefer a direct Index Scan or Bitmap Index Scan on it. BitmapAnd is used when no single index covers all conditions but multiple individual indexes each filter the data significantly.&lt;/p&gt;
&lt;h4 id=&quot;bitmapor--satisfying-or-conditions-with-multiple-indexes&quot;&gt;BitmapOr — Satisfying OR Conditions with Multiple Indexes&lt;/h4&gt;
&lt;p&gt;For &lt;code&gt;OR&lt;/code&gt; conditions, PostgreSQL builds two bitmaps and takes their union:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Bitmap Heap Scan on orders&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Recheck Cond: ((user_id = 42) OR (status = &apos;urgent&apos;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  -&gt;  BitmapOr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        -&gt;  Bitmap Index Scan on orders_user_id_idx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              Index Cond: (user_id = 42)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        -&gt;  Bitmap Index Scan on orders_status_idx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              Index Cond: (status = &apos;urgent&apos;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each index produces a bitmap; &lt;code&gt;BitmapOr&lt;/code&gt; sets a page’s bit if &lt;em&gt;either&lt;/em&gt; bitmap has it set. The heap scan then reads all flagged pages. This is far better than falling back to a seq scan just because of an &lt;code&gt;OR&lt;/code&gt; condition.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An important nuance:&lt;/strong&gt; &lt;code&gt;BitmapOr&lt;/code&gt; can only avoid a seq scan if both sides of the OR have usable indexes. If one condition has no index, the planner may discard the entire strategy and choose a seq scan for the whole table — because it can’t guarantee it won’t miss rows that match the un-indexed condition.&lt;/p&gt;
&lt;h4 id=&quot;when-does-postgresql-choose-bitmap-over-regular-index-scan&quot;&gt;When Does PostgreSQL Choose Bitmap Over Regular Index Scan?&lt;/h4&gt;
&lt;p&gt;The planner models the expected cost of random I/O (index scan) vs. the bitmap setup cost + sequential I/O (bitmap scan). The decision depends on:&lt;/p&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Factor&lt;/th&gt;&lt;th&gt;Pushes toward Index Scan&lt;/th&gt;&lt;th&gt;Pushes toward Bitmap Scan&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Matching rows&lt;/td&gt;&lt;td&gt;Very few (&amp;#x3C; ~1%)&lt;/td&gt;&lt;td&gt;More (1-20%)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Table size&lt;/td&gt;&lt;td&gt;Small&lt;/td&gt;&lt;td&gt;Large&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;random_page_cost&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Low (SSD: 1.1)&lt;/td&gt;&lt;td&gt;High (disk: 4.0)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Physical correlation&lt;/td&gt;&lt;td&gt;High (rows clustered together)&lt;/td&gt;&lt;td&gt;Low (rows scattered)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Multiple filter conditions&lt;/td&gt;&lt;td&gt;Single-column index covers all&lt;/td&gt;&lt;td&gt;Multiple single-column indexes&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;You can observe this tipping point experimentally:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- With low work_mem or high selectivity, see what the planner chooses&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; enable_indexscan &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; off&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;         &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- force bitmap to test its cost&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;EXPLAIN &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;pending&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; enable_bitmapscan &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; off&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;        &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- force seq scan to test its cost  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;EXPLAIN &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;pending&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Reset&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; enable_indexscan &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; on&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; enable_bitmapscan &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; on&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;enable_*&lt;/code&gt; settings don’t &lt;em&gt;forbid&lt;/em&gt; a node — they add a huge cost penalty. They’re a debugging tool, not a production knob. Always reset them after diagnosing a plan.&lt;/p&gt;
&lt;h4 id=&quot;bitmap-scan-and-gingist-indexes&quot;&gt;Bitmap Scan and GIN/GiST Indexes&lt;/h4&gt;
&lt;p&gt;B-tree isn’t the only index type that feeds the bitmap machinery. GIN (used for full-text search, arrays, JSONB) and GiST (used for geometry, ranges, full-text) always use the bitmap approach when scanning — they produce a set of heap locations that gets fed into a Bitmap Heap Scan:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Bitmap Heap Scan on articles&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Recheck Cond: (to_tsvector(&apos;english&apos;, body) @@ &apos;postgresql&apos;::tsquery)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  -&gt;  Bitmap Index Scan on articles_body_fts_idx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        Index Cond: (to_tsvector(&apos;english&apos;, body) @@ &apos;postgresql&apos;::tsquery)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For JSONB and array containment queries, the same pattern applies:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- GIN index on tags array&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; orders_tags_gin_idx&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;USING&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; GIN (tags);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Query uses Bitmap Index Scan via GIN&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; tags @&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ARRAY&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;[&apos;urgent&apos;, &apos;international&apos;];&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;GIN indexes are inherently multi-valued — one index entry can point to many rows, and one row can have many index entries. The bitmap approach naturally handles this many-to-many relationship without duplication.&lt;/p&gt;
&lt;h3 id=&quot;the-decision-tree&quot;&gt;The Decision Tree&lt;/h3&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 844 1294&quot;&gt;&lt;svg class=&quot;d2-676765154 d2-svg&quot; width=&quot;844&quot; height=&quot;1294&quot; viewBox=&quot;-25 -25 844 1294&quot;&gt;&lt;rect x=&quot;-25.000000&quot; y=&quot;-25.000000&quot; width=&quot;844.000000&quot; height=&quot;1294.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-676765154 .text-bold {
	font-family: &quot;d2-676765154-font-bold&quot;;
}
@font-face {
	font-family: d2-676765154-font-bold;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-676765154 .text-italic {
	font-family: &quot;d2-676765154-font-italic&quot;;
}
@font-face {
	font-family: d2-676765154-font-italic;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-676765154 .fill-N1{fill:#0A0F25;}
		.d2-676765154 .fill-N2{fill:#676C7E;}
		.d2-676765154 .fill-N3{fill:#9499AB;}
		.d2-676765154 .fill-N4{fill:#CFD2DD;}
		.d2-676765154 .fill-N5{fill:#DEE1EB;}
		.d2-676765154 .fill-N6{fill:#EEF1F8;}
		.d2-676765154 .fill-N7{fill:#FFFFFF;}
		.d2-676765154 .fill-B1{fill:#0D32B2;}
		.d2-676765154 .fill-B2{fill:#0D32B2;}
		.d2-676765154 .fill-B3{fill:#E3E9FD;}
		.d2-676765154 .fill-B4{fill:#E3E9FD;}
		.d2-676765154 .fill-B5{fill:#EDF0FD;}
		.d2-676765154 .fill-B6{fill:#F7F8FE;}
		.d2-676765154 .fill-AA2{fill:#4A6FF3;}
		.d2-676765154 .fill-AA4{fill:#EDF0FD;}
		.d2-676765154 .fill-AA5{fill:#F7F8FE;}
		.d2-676765154 .fill-AB4{fill:#EDF0FD;}
		.d2-676765154 .fill-AB5{fill:#F7F8FE;}
		.d2-676765154 .stroke-N1{stroke:#0A0F25;}
		.d2-676765154 .stroke-N2{stroke:#676C7E;}
		.d2-676765154 .stroke-N3{stroke:#9499AB;}
		.d2-676765154 .stroke-N4{stroke:#CFD2DD;}
		.d2-676765154 .stroke-N5{stroke:#DEE1EB;}
		.d2-676765154 .stroke-N6{stroke:#EEF1F8;}
		.d2-676765154 .stroke-N7{stroke:#FFFFFF;}
		.d2-676765154 .stroke-B1{stroke:#0D32B2;}
		.d2-676765154 .stroke-B2{stroke:#0D32B2;}
		.d2-676765154 .stroke-B3{stroke:#E3E9FD;}
		.d2-676765154 .stroke-B4{stroke:#E3E9FD;}
		.d2-676765154 .stroke-B5{stroke:#EDF0FD;}
		.d2-676765154 .stroke-B6{stroke:#F7F8FE;}
		.d2-676765154 .stroke-AA2{stroke:#4A6FF3;}
		.d2-676765154 .stroke-AA4{stroke:#EDF0FD;}
		.d2-676765154 .stroke-AA5{stroke:#F7F8FE;}
		.d2-676765154 .stroke-AB4{stroke:#EDF0FD;}
		.d2-676765154 .stroke-AB5{stroke:#F7F8FE;}
		.d2-676765154 .background-color-N1{background-color:#0A0F25;}
		.d2-676765154 .background-color-N2{background-color:#676C7E;}
		.d2-676765154 .background-color-N3{background-color:#9499AB;}
		.d2-676765154 .background-color-N4{background-color:#CFD2DD;}
		.d2-676765154 .background-color-N5{background-color:#DEE1EB;}
		.d2-676765154 .background-color-N6{background-color:#EEF1F8;}
		.d2-676765154 .background-color-N7{background-color:#FFFFFF;}
		.d2-676765154 .background-color-B1{background-color:#0D32B2;}
		.d2-676765154 .background-color-B2{background-color:#0D32B2;}
		.d2-676765154 .background-color-B3{background-color:#E3E9FD;}
		.d2-676765154 .background-color-B4{background-color:#E3E9FD;}
		.d2-676765154 .background-color-B5{background-color:#EDF0FD;}
		.d2-676765154 .background-color-B6{background-color:#F7F8FE;}
		.d2-676765154 .background-color-AA2{background-color:#4A6FF3;}
		.d2-676765154 .background-color-AA4{background-color:#EDF0FD;}
		.d2-676765154 .background-color-AA5{background-color:#F7F8FE;}
		.d2-676765154 .background-color-AB4{background-color:#EDF0FD;}
		.d2-676765154 .background-color-AB5{background-color:#F7F8FE;}
		.d2-676765154 .color-N1{color:#0A0F25;}
		.d2-676765154 .color-N2{color:#676C7E;}
		.d2-676765154 .color-N3{color:#9499AB;}
		.d2-676765154 .color-N4{color:#CFD2DD;}
		.d2-676765154 .color-N5{color:#DEE1EB;}
		.d2-676765154 .color-N6{color:#EEF1F8;}
		.d2-676765154 .color-N7{color:#FFFFFF;}
		.d2-676765154 .color-B1{color:#0D32B2;}
		.d2-676765154 .color-B2{color:#0D32B2;}
		.d2-676765154 .color-B3{color:#E3E9FD;}
		.d2-676765154 .color-B4{color:#E3E9FD;}
		.d2-676765154 .color-B5{color:#EDF0FD;}
		.d2-676765154 .color-B6{color:#F7F8FE;}
		.d2-676765154 .color-AA2{color:#4A6FF3;}
		.d2-676765154 .color-AA4{color:#EDF0FD;}
		.d2-676765154 .color-AA5{color:#F7F8FE;}
		.d2-676765154 .color-AB4{color:#EDF0FD;}
		.d2-676765154 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-676765154);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-676765154);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-676765154);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-676765154);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-676765154);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-676765154);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-676765154);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-676765154);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-676765154);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-676765154);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-676765154);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-676765154);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-676765154);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-676765154);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-676765154);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-676765154);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-676765154);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-676765154);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;QQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;109.000000&quot; y=&quot;0.000000&quot; width=&quot;249.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;233.500000&quot; y=&quot;38.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Query with WHERE condition&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Qg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;path d=&quot;M 233 290 C 232 290 231 290 231 290 L 99 229 C 98 228 98 227 99 227 L 231 166 C 232 165 235 165 236 166 L 367 226 C 368 227 368 228 367 228 L 235 290 C 235 290 234 290 233 290 Z&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#CFD2DD&quot; class=&quot;stroke-B1 fill-N4&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;text x=&quot;233.000000&quot; y=&quot;225.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;233.000000&quot; dy=&quot;0.000000&quot;&gt;Index exists&lt;/tspan&gt;&lt;tspan x=&quot;233.000000&quot; dy=&quot;18.500000&quot;&gt;on filter column?&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;RA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;path d=&quot;M 335 535 C 334 535 333 535 333 535 L 213 474 C 212 473 212 472 213 472 L 333 411 C 334 410 336 410 337 411 L 457 471 C 458 472 458 473 457 473 L 337 535 C 337 535 336 535 335 535 Z&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#CFD2DD&quot; class=&quot;stroke-B1 fill-N4&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;text x=&quot;335.000000&quot; y=&quot;470.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;335.000000&quot; dy=&quot;0.000000&quot;&gt;What fraction&lt;/tspan&gt;&lt;tspan x=&quot;335.000000&quot; dy=&quot;18.500000&quot;&gt;of rows match?&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;RQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;path d=&quot;M 633 796 C 632 796 632 796 631 796 L 536 735 C 535 734 535 733 536 733 L 631 672 C 632 671 634 671 635 672 L 730 732 C 731 733 731 734 730 734 L 635 796 C 634 796 634 796 633 796 Z&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#CFD2DD&quot; class=&quot;stroke-B1 fill-N4&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;text x=&quot;633.000000&quot; y=&quot;731.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;633.000000&quot; dy=&quot;0.000000&quot;&gt;All columns&lt;/tspan&gt;&lt;tspan x=&quot;633.000000&quot; dy=&quot;18.500000&quot;&gt;in index?&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;SQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;path d=&quot;M 132 1041 C 131 1041 130 1041 130 1041 L 1 980 C 0 979 0 978 1 978 L 130 917 C 131 916 133 916 135 917 L 264 977 C 265 978 265 979 264 979 L 134 1041 C 134 1041 133 1041 132 1041 Z&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#CFD2DD&quot; class=&quot;stroke-B1 fill-N4&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;text x=&quot;132.000000&quot; y=&quot;976.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;132.000000&quot; dy=&quot;0.000000&quot;&gt;Multiple indexes&lt;/tspan&gt;&lt;tspan x=&quot;132.000000&quot; dy=&quot;18.500000&quot;&gt;available?&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Rg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;413.000000&quot; y=&quot;938.000000&quot; width=&quot;158.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;492.000000&quot; y=&quot;976.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;492.000000&quot; dy=&quot;0.000000&quot;&gt;Index Only Scan&lt;/tspan&gt;&lt;tspan x=&quot;492.000000&quot; dy=&quot;18.500000&quot;&gt;fastest&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Rw==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;631.000000&quot; y=&quot;938.000000&quot; width=&quot;163.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;712.500000&quot; y=&quot;976.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;712.500000&quot; dy=&quot;0.000000&quot;&gt;Index Scan&lt;/tspan&gt;&lt;tspan x=&quot;712.500000&quot; dy=&quot;18.500000&quot;&gt;random heap I/O&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;SA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;268.000000&quot; y=&quot;693.000000&quot; width=&quot;176.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;356.000000&quot; y=&quot;731.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;356.000000&quot; dy=&quot;0.000000&quot;&gt;Bitmap Index Scan&lt;/tspan&gt;&lt;tspan x=&quot;356.000000&quot; dy=&quot;18.500000&quot;&gt;batch heap reads&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Qw==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;78.000000&quot; y=&quot;701.000000&quot; width=&quot;109.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;132.500000&quot; y=&quot;739.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Seq Scan&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Sg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;29.000000&quot; y=&quot;1162.000000&quot; width=&quot;206.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;132.000000&quot; y=&quot;1200.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;132.000000&quot; dy=&quot;0.000000&quot;&gt;BitmapAnd / BitmapOr&lt;/tspan&gt;&lt;tspan x=&quot;132.000000&quot; dy=&quot;18.500000&quot;&gt;combine indexes&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgQilbMF0=&quot;&gt;&lt;marker id=&quot;mk-d2-676765154-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 233.250000 68.000000 C 233.250000 106.000000 233.199997 125.800003 233.020408 161.000052&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-676765154-3488378134)&quot; mask=&quot;url(#d2-676765154)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgQylbMF0=&quot;&gt;&lt;path d=&quot;M 188.583557 272.411981 C 126.198997 334.600006 110.250000 375.000000 110.250000 411.750000 C 110.250000 448.500000 113.449997 623.099976 125.605472 697.552268&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-676765154-3488378134)&quot; mask=&quot;url(#d2-676765154)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;111.000000&quot; y=&quot;478.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;No&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgRClbMF0=&quot;&gt;&lt;path d=&quot;M 272.267562 274.547025 C 321.799988 335.000000 334.600006 362.399994 334.966388 406.000141&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-676765154-3488378134)&quot; mask=&quot;url(#d2-676765154)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;321.000000&quot; y=&quot;340.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Yes&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEQgLSZndDsgRSlbMF0=&quot;&gt;&lt;path d=&quot;M 402.831678 502.803090 C 586.200012 583.200012 632.599976 617.000000 632.970369 667.000110&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-676765154-3488378134)&quot; mask=&quot;url(#d2-676765154)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;545.000000&quot; y=&quot;562.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;545.000000&quot; dy=&quot;0.000000&quot;&gt;Very small&lt;/tspan&gt;&lt;tspan x=&quot;545.000000&quot; dy=&quot;18.500000&quot;&gt;&amp;#x3C; ~1%&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEUgLSZndDsgRilbMF0=&quot;&gt;&lt;path d=&quot;M 589.492262 771.314049 C 511.600006 839.200012 491.750000 872.900024 491.750000 934.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-676765154-3488378134)&quot; mask=&quot;url(#d2-676765154)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;512.000000&quot; y=&quot;844.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Yes&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEUgLSZndDsgRylbMF0=&quot;&gt;&lt;path d=&quot;M 663.078260 779.684445 C 702.200012 840.799988 712.250000 872.900024 712.250000 934.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-676765154-3488378134)&quot; mask=&quot;url(#d2-676765154)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;706.000000&quot; y=&quot;858.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;No&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEQgLSZndDsgSClbMF0=&quot;&gt;&lt;path d=&quot;M 345.306675 532.976348 C 354.000000 589.000000 356.250000 621.500000 356.250000 689.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-676765154-3488378134)&quot; mask=&quot;url(#d2-676765154)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;356.000000&quot; y=&quot;609.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;356.000000&quot; dy=&quot;0.000000&quot;&gt;Small-medium&lt;/tspan&gt;&lt;tspan x=&quot;356.000000&quot; dy=&quot;18.500000&quot;&gt;~1-20%&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEQgLSZndDsgQylbMF0=&quot;&gt;&lt;path d=&quot;M 287.507212 514.331009 C 207.800003 585.400024 179.300003 623.099976 148.043807 697.809924&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-676765154-3488378134)&quot; mask=&quot;url(#d2-676765154)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;200.500000&quot; y=&quot;592.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;200.500000&quot; dy=&quot;0.000000&quot;&gt;Large&lt;/tspan&gt;&lt;tspan x=&quot;200.500000&quot; dy=&quot;18.500000&quot;&gt;&gt; ~20%&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEMgLSZndDsgSSlbMF0=&quot;&gt;&lt;path d=&quot;M 126.192586 768.476233 C 115.300003 838.500000 114.599998 869.200012 122.347443 916.053588&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-676765154-3488378134)&quot; mask=&quot;url(#d2-676765154)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEkgLSZndDsgSilbMF0=&quot;&gt;&lt;path d=&quot;M 132.000000 1043.000000 C 132.000000 1089.400024 132.000000 1113.699951 132.000000 1158.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-676765154-3488378134)&quot; mask=&quot;url(#d2-676765154)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;132.500000&quot; y=&quot;1107.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Yes + AND/OR conditions&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEkgLSZndDsgQylbMF0=&quot;&gt;&lt;path d=&quot;M 193.698903 941.944667 C 303.399994 873.799988 302.250000 838.500000 189.648561 768.609451&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-676765154-3488378134)&quot; mask=&quot;url(#d2-676765154)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;303.000000&quot; y=&quot;859.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;No&lt;/text&gt;&lt;/g&gt;&lt;mask id=&quot;d2-676765154&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;844&quot; height=&quot;1294&quot;&gt;
&lt;rect x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;844&quot; height=&quot;1294&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;100.000000&quot; y=&quot;462.000000&quot; width=&quot;22&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;308.000000&quot; y=&quot;324.000000&quot; width=&quot;26&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;509.000000&quot; y=&quot;546.000000&quot; width=&quot;72&quot; height=&quot;37&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;499.000000&quot; y=&quot;828.000000&quot; width=&quot;26&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;695.000000&quot; y=&quot;842.000000&quot; width=&quot;22&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;306.000000&quot; y=&quot;593.000000&quot; width=&quot;100&quot; height=&quot;37&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;175.000000&quot; y=&quot;576.000000&quot; width=&quot;51&quot; height=&quot;37&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;51.000000&quot; y=&quot;1091.000000&quot; width=&quot;163&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;292.000000&quot; y=&quot;843.000000&quot; width=&quot;22&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;hr&gt;
&lt;h2 id=&quot;join-strategies&quot;&gt;Join Strategies&lt;/h2&gt;
&lt;p&gt;Plans with joins show how PostgreSQL combined the two row sets. There are three strategies:&lt;/p&gt;
&lt;h3 id=&quot;nested-loop-join&quot;&gt;Nested Loop Join&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Nested Loop  (cost=0.43..45.80 rows=10 width=64)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  -&gt;  Index Scan using users_pkey on users  (rows=1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  -&gt;  Index Scan using orders_user_id_idx on orders  (rows=10)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        Index Cond: (user_id = users.id)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For each row from the outer side (users), scan the inner side (orders) for matching rows. &lt;code&gt;loops&lt;/code&gt; on the inner node = number of outer rows. Best when outer side is small and inner side has a good index.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Trap:&lt;/strong&gt; If the outer side returns thousands of rows and the inner has no index, this becomes O(N×M) — catastrophic.&lt;/p&gt;
&lt;h3 id=&quot;hash-join&quot;&gt;Hash Join&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Hash Join  (cost=1240.00..16500.00 rows=100000 width=16)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Hash Cond: (o.user_id = u.id)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  -&gt;  Seq Scan on orders o&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  -&gt;  Hash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        -&gt;  Index Scan on users u&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Build a hash table from the smaller side (users), then probe it with each row from the larger side (orders). One pass over each side. Memory cost is the hash table — if it doesn’t fit in &lt;code&gt;work_mem&lt;/code&gt;, it spills to disk (&lt;code&gt;Batches: N&lt;/code&gt; where N &gt; 1).&lt;/p&gt;
&lt;p&gt;Best for large joins where neither side is tiny.&lt;/p&gt;
&lt;h3 id=&quot;merge-join&quot;&gt;Merge Join&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Merge Join  (cost=24000.00..32000.00 rows=50000 width=64)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Merge Cond: (o.user_id = u.id)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  -&gt;  Sort on users.id&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  -&gt;  Sort on orders.user_id&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sort both sides on the join key, then merge them like merge sort’s combine step. Efficient when both inputs are already sorted (e.g., from an index scan on the join key) or when both sides are large and a hash table wouldn’t fit in memory.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;other-node-types-youll-see&quot;&gt;Other Node Types You’ll See&lt;/h2&gt;





















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Node&lt;/th&gt;&lt;th&gt;What It Does&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;Sort&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Sorts rows. Shows &lt;code&gt;Sort Method&lt;/code&gt; and memory used. If &lt;code&gt;external merge&lt;/code&gt; appears, it spilled to disk — increase &lt;code&gt;work_mem&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;HashAggregate&lt;/code&gt;&lt;/td&gt;&lt;td&gt;GROUP BY using a hash table. Shows &lt;code&gt;Batches&lt;/code&gt; — if &gt; 1, it spilled.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;GroupAggregate&lt;/code&gt;&lt;/td&gt;&lt;td&gt;GROUP BY on pre-sorted input. Lower memory, requires sorted input.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;Aggregate&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Simple aggregates (COUNT, SUM) with no grouping.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;Limit&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Stops when N rows collected. Affects how much of the plan below it actually runs.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;Materialize&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Caches a node’s output in memory so it can be scanned multiple times (e.g., inner side of a nested loop).&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;Subquery Scan&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Scans the result of a subquery as if it’s a table.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;CTE Scan&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Reads from a materialized CTE. PostgreSQL 12+ inlines most CTEs unless you use &lt;code&gt;MATERIALIZED&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;Function Scan&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Result of a set-returning function, e.g. &lt;code&gt;generate_series()&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;Gather&lt;/code&gt; / &lt;code&gt;Gather Merge&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Collects results from parallel workers.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;Parallel Seq Scan&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Seq scan split across multiple parallel workers.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&quot;explain-options-reference&quot;&gt;EXPLAIN Options Reference&lt;/h2&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Basic plan (no execution)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;EXPLAIN &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ...;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Execute and time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;EXPLAIN ANALYZE &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ...;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Full diagnostics — use this by default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;EXPLAIN (ANALYZE, BUFFERS) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ...;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- JSON output — useful for tooling, pg_query, etc.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;EXPLAIN (ANALYZE, BUFFERS, FORMAT &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;JSON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ...;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Show verbose node output (output columns, schema-qualified names)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;EXPLAIN (ANALYZE, &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;VERBOSE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ...;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Show row-level settings (e.g. if JIT kicked in)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;EXPLAIN (ANALYZE, BUFFERS, SETTINGS) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ...;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Include WAL stats (useful for INSERT/UPDATE/DELETE plans)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;EXPLAIN (ANALYZE, WAL) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;UPDATE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;done&apos;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 42&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;code&gt;WAL&lt;/code&gt;, &lt;code&gt;BUFFERS&lt;/code&gt;, &lt;code&gt;TIMING&lt;/code&gt;, and &lt;code&gt;VERBOSE&lt;/code&gt; only emit data when run with &lt;code&gt;ANALYZE&lt;/code&gt; — without it, the query is only planned, never executed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;One gotcha with EXPLAIN ANALYZE on write queries:&lt;/strong&gt; it actually executes the DML. Wrap in a transaction and roll back:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;BEGIN&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;EXPLAIN ANALYZE &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;UPDATE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;done&apos;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; user_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 42&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ROLLBACK&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;identifying-the-bottleneck&quot;&gt;Identifying the Bottleneck&lt;/h2&gt;
&lt;p&gt;The plan can have dozens of nodes. Here’s a systematic way to find what’s costing you:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Find the slowest node.&lt;/strong&gt; Look at &lt;code&gt;actual time&lt;/code&gt; on each node. The difference between a node’s time and its children’s times is the work that node itself did. A node with &lt;code&gt;actual time=480ms&lt;/code&gt; whose children took &lt;code&gt;actual time=210ms&lt;/code&gt; spent 270ms doing its own work (e.g., the hash join probe).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Compare estimated vs actual rows.&lt;/strong&gt; A large discrepancy indicates the planner had bad statistics and may have chosen the wrong plan:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Seq Scan on orders  (cost=0.00..8820.00 rows=200 width=40)   -- planner estimated 200&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    (actual time=0.012..412.340 rows=198234 loops=1)  -- actually 198k!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The planner thought it was dealing with 200 rows and may have chosen a nested loop join that’s catastrophic with 198k rows. Fix: &lt;code&gt;ANALYZE orders;&lt;/code&gt; or investigate why statistics are wrong.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Look for &lt;code&gt;loops&lt;/code&gt; multiplied cost.&lt;/strong&gt; A node showing &lt;code&gt;actual time=0.05 loops=5000&lt;/code&gt; costs &lt;code&gt;5000 × 0.05 = 250ms&lt;/code&gt; total.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Look for spills.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Sort Method: external merge&lt;/code&gt; — sort spilled to disk. Increase &lt;code&gt;work_mem&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HashAggregate: Batches: 4&lt;/code&gt; — hash aggregate spilled. Increase &lt;code&gt;work_mem&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Bitmap Heap Scan: Heap Blocks: exact=100 lossy=4000&lt;/code&gt; — bitmap went lossy. Increase &lt;code&gt;work_mem&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;5. Look for filter removals.&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Filter: (status = &apos;active&apos;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Rows Removed by Filter: 199500&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Reading 200k rows and keeping 500 means a seq scan is doing huge unnecessary work. An index on &lt;code&gt;status&lt;/code&gt; would help — but only if &lt;code&gt;status&lt;/code&gt; is selective enough.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-gotchas-when-indexes-get-ignored&quot;&gt;The Gotchas: When Indexes Get Ignored&lt;/h2&gt;
&lt;p&gt;These are the situations that catch engineers off guard. You add an index, but &lt;code&gt;EXPLAIN&lt;/code&gt; still shows a seq scan or the index isn’t used the way you expect.&lt;/p&gt;
&lt;h3 id=&quot;1-like-with-a-leading-wildcard&quot;&gt;1. &lt;code&gt;LIKE&lt;/code&gt; with a leading wildcard&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Uses the index (prefix match)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; users &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; email &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;LIKE&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;john%&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- IGNORES the index (leading wildcard can&apos;t be found in a B-tree)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; users &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; email &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;LIKE&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;%@example.com&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;B-tree indexes store values in sorted order. A leading wildcard means “could be anything before this pattern” — there’s no sorted prefix to binary-search on. The full table must be scanned.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; For suffix/substring matching, use &lt;code&gt;pg_trgm&lt;/code&gt; (trigram) index:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; EXTENSION &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;IF&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; NOT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; EXISTS&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pg_trgm;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; users_email_trgm_idx&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; users &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;USING&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; GIN (email gin_trgm_ops);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Now LIKE &apos;%@example.com&apos; can use the trigram index&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;2-function-applied-to-the-indexed-column&quot;&gt;2. Function applied to the indexed column&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Ignores the index on created_at&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; DATE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(created_at) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;2025-01-01&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Uses the index&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;2025-01-01&apos;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;2025-01-02&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you wrap a column in a function, PostgreSQL can’t use a plain B-tree index on the column — the index stores raw &lt;code&gt;created_at&lt;/code&gt; values, not &lt;code&gt;DATE(created_at)&lt;/code&gt; values.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fix option 1:&lt;/strong&gt; Rewrite the query to not use the function on the column side (as above).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fix option 2:&lt;/strong&gt; Create a functional index that stores the expression result:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; orders_date_idx&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders (&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;DATE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(created_at));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Now DATE(created_at) = &apos;2025-01-01&apos; uses the index&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The same pattern applies to &lt;code&gt;LOWER(email)&lt;/code&gt;, &lt;code&gt;UPPER(name)&lt;/code&gt;, &lt;code&gt;EXTRACT(year FROM date)&lt;/code&gt;, etc.&lt;/p&gt;
&lt;h3 id=&quot;3-type-mismatch--implicit-cast&quot;&gt;3. Type mismatch / implicit cast&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Column is INTEGER, but you pass a string&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; user_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;42&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;  &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- implicit cast may prevent index use&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Safer: explicit type match&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; user_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 42&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s the &lt;strong&gt;column-side&lt;/strong&gt; cast that breaks index use. &lt;code&gt;WHERE id = &apos;42&apos;&lt;/code&gt; (literal cast) works — Postgres folds the constant to int. &lt;code&gt;WHERE id::text = &apos;42&apos;&lt;/code&gt; (column cast) doesn’t — Postgres has to compute &lt;code&gt;id::text&lt;/code&gt; for every row before comparing, defeating the index.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Particularly common with:&lt;/strong&gt; numeric columns passed string literals from ORMs, &lt;code&gt;VARCHAR&lt;/code&gt; vs &lt;code&gt;TEXT&lt;/code&gt;, &lt;code&gt;TIMESTAMP&lt;/code&gt; vs &lt;code&gt;TIMESTAMPTZ&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Check this in pg_stats: if you&apos;re joining two columns with different types,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- the planner may not be able to estimate selectivity well&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; tablename, attname, atttypid::regtype&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pg_attribute &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;JOIN&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pg_class &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; attrelid &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; pg_class&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;oid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; relname &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;orders&apos;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; attname &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;user_id&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;4-or-conditions&quot;&gt;4. OR conditions&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Can&apos;t use a single index efficiently — often falls back to seq scan&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; user_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 42&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; OR&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;pending&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;PostgreSQL &lt;em&gt;can&lt;/em&gt; handle this with a &lt;code&gt;BitmapOr&lt;/code&gt; if both columns are indexed, but it requires two separate index scans and a bitmap combine. If the individual conditions are not very selective, a seq scan may still win. Rewrite as &lt;code&gt;UNION ALL&lt;/code&gt; when you need two genuinely independent conditions:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; user_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 42&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;UNION ALL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;pending&apos;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; user_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 42&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;5-not-in-and---on-indexed-columns&quot;&gt;5. &lt;code&gt;NOT IN&lt;/code&gt; and &lt;code&gt;!= &lt;/code&gt; on indexed columns&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Ignores the index — negation has no useful range in a B-tree&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;cancelled&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Also ignores the index&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; user_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;NOT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; IN&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A B-tree is optimized for finding values, not for finding the absence of a value. &lt;code&gt;NOT IN&lt;/code&gt; with a large subquery is particularly dangerous — it can prevent index use entirely and generate a cross-product in the plan.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Rewrite using &lt;code&gt;LEFT JOIN ... WHERE right_id IS NULL&lt;/code&gt; instead of &lt;code&gt;NOT IN&lt;/code&gt; with subqueries:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Slow: NOT IN with subquery — disables index, doesn&apos;t handle NULLs well&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; users &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;NOT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; IN&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; user_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; banned_users);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Fast: anti-join&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; u.&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; users u&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;LEFT JOIN&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; banned_users b &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ON&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; b&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;user_id&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; u&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;id&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; b&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;user_id&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; IS&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; NULL&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;6-null-comparisons&quot;&gt;6. NULL comparisons&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- IS NULL / IS NOT NULL can use an index, but only if the index includes NULL values&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- B-tree indexes DO include NULLs (unlike some other databases)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; completed_at &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;IS&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; NULL&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;  &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- can use index on completed_at&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;PostgreSQL B-tree indexes include NULL entries, so &lt;code&gt;IS NULL&lt;/code&gt; and &lt;code&gt;IS NOT NULL&lt;/code&gt; can use them. However, partial indexes specifically excluding or including NULLs are more efficient for heavily NULL-skewed columns:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Partial index: only rows where completed_at IS NULL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Much smaller index, only used by queries filtering for NULL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; orders_pending_idx&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders (id) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; completed_at &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;IS&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; NULL&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;7-statistics-are-stale&quot;&gt;7. Statistics are stale&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Force a statistics refresh on a table&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;ANALYZE orders;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Check when statistics were last collected&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; schemaname, tablename, last_analyze, last_autoanalyze&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pg_stat_user_tables&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; tablename &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;orders&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Check the n_distinct and correlation for a column&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; attname, n_distinct, correlation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pg_stats&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; tablename &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;orders&apos;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; attname &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;user_id&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;n_distinct&lt;/code&gt; tells the planner how many distinct values exist. If it’s wrong (e.g., says 200 but there are actually 200,000), the planner will massively under-estimate the selectivity of &lt;code&gt;user_id = 42&lt;/code&gt; and may choose a seq scan.&lt;/p&gt;
&lt;p&gt;For columns with very many distinct values, the default &lt;code&gt;default_statistics_target = 100&lt;/code&gt; may be too low. Increase it for a specific column:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ALTER&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; TABLE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ALTER&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; COLUMN user_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; STATISTICS&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 500&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;ANALYZE orders;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;8-the-planner-disables-an-index-due-to-cost-settings&quot;&gt;8. The planner disables an index due to cost settings&lt;/h3&gt;
&lt;p&gt;Two settings control when the planner chooses random I/O:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Default: 4.0 (calibrated for spinning disks)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- On SSDs, set to 1.1 — makes index scans much more attractive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; random_page_cost &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- You can also set per-session for testing&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; random_page_cost &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;EXPLAIN (ANALYZE, BUFFERS) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ...;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;RESET&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; random_page_cost;  &lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- or use SET LOCAL inside a transaction&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If your server has SSDs but &lt;code&gt;random_page_cost&lt;/code&gt; is still 4.0, the planner is systematically undervaluing index scans. Many cloud PostgreSQL setups (RDS, Cloud SQL) run on SSDs but don’t override this default.&lt;/p&gt;
&lt;h3 id=&quot;9-partial-indexes-not-being-used&quot;&gt;9. Partial indexes not being used&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; orders_pending_idx&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders (created_at) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;pending&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Uses the partial index&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;pending&apos;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; NOW&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; INTERVAL &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;7 days&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Does NOT use it (status is not in the WHERE clause)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; orders &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; NOW&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; INTERVAL &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;7 days&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A partial index only applies to queries whose &lt;code&gt;WHERE&lt;/code&gt; clause implies the index’s predicate. If your query doesn’t include the filter condition from the index definition, PostgreSQL won’t consider it.&lt;/p&gt;
&lt;h3 id=&quot;10-ilike-and-case-insensitive-patterns&quot;&gt;10. &lt;code&gt;ILIKE&lt;/code&gt; and case-insensitive patterns&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- ILIKE uses a case-insensitive match — ignores a plain B-tree index&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; users &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; email ILIKE &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;john%&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A plain B-tree index on &lt;code&gt;email&lt;/code&gt; is case-sensitive. &lt;code&gt;ILIKE&lt;/code&gt; requires comparing lowercase-folded values, which the raw index doesn’t store.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fix options:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Option 1: functional index on lower()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; users_email_lower_idx&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; users (&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;LOWER&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(email));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; users &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; LOWER&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(email) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;LIKE&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;john%&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Option 2: citext extension&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; EXTENSION citext;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ALTER&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; TABLE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; users &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ALTER&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; COLUMN email &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;TYPE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; citext;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Now regular = and LIKE are case-insensitive and use the B-tree index&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Option 3: trigram index with gin_trgm_ops (handles ILIKE &apos;%pattern%&apos; too)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; users_email_trgm_idx&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; users &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;USING&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; GIN (email gin_trgm_ops);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;practical-workflow-diagnosing-a-slow-query&quot;&gt;Practical Workflow: Diagnosing a Slow Query&lt;/h2&gt;
&lt;p&gt;When a query is slow, here’s the exact workflow to follow:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Get the full plan with BUFFERS&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;EXPLAIN (ANALYZE, BUFFERS) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;your query&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Find the most expensive node.&lt;/strong&gt; Look at the &lt;code&gt;actual time&lt;/code&gt; on each node. The root node’s time minus its children’s times = that node’s own work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Check for row estimate mismatches.&lt;/strong&gt; If &lt;code&gt;rows=200&lt;/code&gt; in the plan but &lt;code&gt;actual rows=200000&lt;/code&gt;, your statistics are stale or the planner has wrong assumptions. Run &lt;code&gt;ANALYZE &amp;#x3C;table&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4: Look for seq scans on large tables.&lt;/strong&gt; Check if there’s a filter removing most rows — that’s your index opportunity.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 5: Check &lt;code&gt;Buffers: read&lt;/code&gt;&lt;/strong&gt; — high read counts mean disk I/O. Consider whether the working set fits in &lt;code&gt;shared_buffers&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 6: Look for spills&lt;/strong&gt; — &lt;code&gt;external merge&lt;/code&gt; in sort, &lt;code&gt;Batches &gt; 1&lt;/code&gt; in hash operations. Increase &lt;code&gt;work_mem&lt;/code&gt; for the session and re-run:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; work_mem &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;256MB&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;EXPLAIN (ANALYZE, BUFFERS) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;your query&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 7: If index exists but isn’t used, check:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Is the column wrapped in a function?&lt;/li&gt;
&lt;li&gt;Is there a type mismatch?&lt;/li&gt;
&lt;li&gt;Is selectivity too low? (Query returns &gt;15% of rows)&lt;/li&gt;
&lt;li&gt;Is &lt;code&gt;random_page_cost&lt;/code&gt; misconfigured for your storage?&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;ANALYZE &amp;#x3C;table&gt;&lt;/code&gt; and check again.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;using-explaindepeszcom-and-pev2&quot;&gt;Using explain.depesz.com and pev2&lt;/h2&gt;
&lt;p&gt;Reading raw text output works, but for complex plans there are better tools:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://explain.depesz.com&quot;&gt;explain.depesz.com&lt;/a&gt;&lt;/strong&gt; — paste your &lt;code&gt;EXPLAIN ANALYZE&lt;/code&gt; output and get a color-coded breakdown. Highlights the slowest nodes, shows estimated vs actual rows side by side. The go-to tool for sharing plans with teammates.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://explain.dalibo.com&quot;&gt;PEV2 (Postgres Explain Visualizer 2)&lt;/a&gt;&lt;/strong&gt; — a more modern visual tree. Shows the plan as a node graph with timing proportional to node width. Particularly good for plans with many joins.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;pgBadger / pg_stat_statements&lt;/strong&gt; — for identifying which queries are slow in aggregate over time (not just one-off analysis):&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Enable pg_stat_statements in postgresql.conf:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- shared_preload_libraries = &apos;pg_stat_statements&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Find your top 10 slowest queries by total time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; query, calls, total_exec_time, mean_exec_time, &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;rows&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pg_stat_statements&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;ORDER BY&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; total_exec_time &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;DESC&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;LIMIT&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;quick-reference&quot;&gt;Quick Reference&lt;/h2&gt;





















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Plan output&lt;/th&gt;&lt;th&gt;What to look for&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;Seq Scan&lt;/code&gt; + large &lt;code&gt;Rows Removed by Filter&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Missing index on filter column&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;rows=100&lt;/code&gt; but &lt;code&gt;actual rows=100000&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Stale statistics — run &lt;code&gt;ANALYZE&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;loops=500&lt;/code&gt; on inner node&lt;/td&gt;&lt;td&gt;Nested loop with large outer side — check for index on join column&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;Sort Method: external merge&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Sort spilled to disk — increase &lt;code&gt;work_mem&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;Batches: 4&lt;/code&gt; on HashAggregate/Hash Join&lt;/td&gt;&lt;td&gt;Hash spilled to disk — increase &lt;code&gt;work_mem&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;Heap Blocks: lossy=N&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Bitmap went lossy — increase &lt;code&gt;work_mem&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;Heap Fetches: 0&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Index-only scan — best case, keep your visibility map current&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;shared read=N&lt;/code&gt; (large)&lt;/td&gt;&lt;td&gt;Heavy disk I/O — check &lt;code&gt;shared_buffers&lt;/code&gt;, consider caching&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;Buffers: temp read/written&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Operator spilled to temp files&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;Gather&lt;/code&gt; / &lt;code&gt;Parallel&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Query is using parallel workers — check &lt;code&gt;max_parallel_workers_per_gather&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Index exists, seq scan chosen&lt;/td&gt;&lt;td&gt;Check selectivity, &lt;code&gt;random_page_cost&lt;/code&gt;, stale stats, function on column&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&quot;related-reading&quot;&gt;Related reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/postgres-indexing/&quot;&gt;PostgreSQL Indexing Deep Dive&lt;/a&gt; — the index types whose plan nodes you’re now reading.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/db-storage-and-indexing/&quot;&gt;How Databases Actually Store and Find Your Data&lt;/a&gt; — pages, heaps, TIDs — the substrate of every plan.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/btrees-and-bplus-trees/&quot;&gt;B-Trees and B+ Trees&lt;/a&gt; — why “Index Scan” is so cheap on B+ tree leaves.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/acid-properties-and-isolation-levels/&quot;&gt;ACID, Read Phenomena, Isolation Levels&lt;/a&gt; — when query plans interact with concurrent transactions.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/postgres-partitioning/&quot;&gt;Postgres Partitioning: Strategies, Advantages, and Pitfalls&lt;/a&gt; — how &lt;code&gt;Append&lt;/code&gt;, partition pruning, and &lt;code&gt;Subplans Removed&lt;/code&gt; show up in EXPLAIN.&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>How Databases Actually Store and Find Your Data</title><link>https://abhimanyunagurkar.com/blog/db-storage-and-indexing/</link><guid isPermaLink="true">https://abhimanyunagurkar.com/blog/db-storage-and-indexing/</guid><description>A bottom-up look at how databases physically store data — pages, heaps, B-trees, clustered indexes, and row IDs.</description><pubDate>Mon, 20 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When you write &lt;code&gt;SELECT * FROM orders WHERE id = 42&lt;/code&gt;, you’re thinking in tables and rows. The database is thinking in pages, heaps, and B-trees. Understanding the gap between those two views explains every performance decision you’ll ever make about indexes.&lt;/p&gt;
&lt;p&gt;Let’s build the picture from the ground up.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-table-a-logical-abstraction&quot;&gt;The Table: A Logical Abstraction&lt;/h2&gt;
&lt;p&gt;A table is a logical concept — a named collection of rows with defined columns. It says nothing about how data is physically stored. Two databases can expose the exact same &lt;code&gt;CREATE TABLE&lt;/code&gt; syntax and store the data in completely different ways underneath.&lt;/p&gt;
&lt;p&gt;The physical reality lives one level down, in &lt;strong&gt;pages&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;pages-the-unit-of-io&quot;&gt;Pages: The Unit of I/O&lt;/h2&gt;
&lt;p&gt;Databases never read a single row from disk. They read a &lt;strong&gt;page&lt;/strong&gt; — a fixed-size block of data, typically 8KB (PostgreSQL, SQL Server) or 16KB (MySQL InnoDB). A page is the smallest unit the storage engine reads or writes.&lt;/p&gt;
&lt;p&gt;A page contains a header, a slot array pointing to row locations, and the actual row data:&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 2038 232&quot;&gt;&lt;svg class=&quot;d2-840467138 d2-svg&quot; width=&quot;2038&quot; height=&quot;232&quot; viewBox=&quot;-15 -45 2038 232&quot;&gt;&lt;rect x=&quot;-15.000000&quot; y=&quot;-45.000000&quot; width=&quot;2038.000000&quot; height=&quot;232.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-840467138 .text {
	font-family: &quot;d2-840467138-font-regular&quot;;
}
@font-face {
	font-family: d2-840467138-font-regular;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-840467138 .text-bold {
	font-family: &quot;d2-840467138-font-bold&quot;;
}
@font-face {
	font-family: d2-840467138-font-bold;
	src: url(&quot;data:application/font-woff;base64,d09GRgABAAAAABLIAAoAAAAAHBgAAguFAAAAAAAAAAAAAAAAAAAAAAAAAABPUy8yAAAA9AAAAGAAAABgXxHXrmNtYXAAAAFUAAAA7QAAAUQnGyn+Z2x5ZgAAAkQAAAuHAAAPtFVNLppoZWFkAAANzAAAADYAAAA2G38e1GhoZWEAAA4EAAAAJAAAACQKfwX2aG10eAAADigAAADFAAAA3GkBChFsb2NhAAAO8AAAAHAAAABwdEx4XG1heHAAAA9gAAAAIAAAACAATwD3bmFtZQAAD4AAAAMoAAAIKgjwVkFwb3N0AAASqAAAAB0AAAAg/9EAMgADAioCvAAFAAACigJYAAAASwKKAlgAAAFeADIBKQAAAgsHAwMEAwICBGAAAvcAAAADAAAAAAAAAABBREJPACAAIP//Au7/BgAAA9gBESAAAZ8AAAAAAfAClAAAACAAA3iclM7JLuMBHMDxz3/aztqZ6Uxn66z/zqalpTQRy4mISFyEozg4iotIRDyGeAEn2wtwEMszcBZeAA8gfpLGwdX3/km+SGQkyMsmfWhIZRWkqmrqmvoNGjZi1JhxE6ZMmzFnwZJlK2mxvBaBVKUlGnoNGHogJlti1rzFe7EaERdycRO3cR2XcRXHcRSHcRD7sRe7cRonsRPbsRWbsXFeOltvPT6uRF2nig6pst/++Ouf/9pUtXsiIyvnqWeee+GlLg2v5L32xlsF77xX9MFHn3z2RclX33z3w0+/1HTr0eQOAAD//wEAAP//kS0+OgAAAHicZFd9bBvneX/elxQvoihLx68jKX7e8T5IiaTI4/EkihJFi6Q+LOrDsi05piRHiB3H8tdsOVISexkQbdkSFdkiw/PibdmMBsiKZEMWFOgyeB/B2s6o0f3hZgaGtWnawujqAdU6pSgS6VjcHSVbyR/UKxyeez5+z+/5Pe9BA0wA4AV8DQzQCC1gBQeASIZIVuR5hpBFWWYog8wjkpjAVuXtr/MRYyRijAZvBF6Yn0eVOXxt+8yxysLCr+d7epS//IcPla+hSx8C4NrnAHgAr0EjkAA2QuQ5jmdMJoNNtDE8Qzxofa2lua3ZaHF/fvf9u38ufFdAI7lc8pyYPqv8Pl7bXrp5EwDAABUAnMNrQIIHaDU3MeV0OuwmwqEdJsYgpjJSmmMYUkxpZ+WT4pn+mJAaKF4cnC9lkql0eer5XO8UXvOV8+1TLcbmA4WBQxH0SpThgsrMTDsLgLU4o3gNzDoC9SgmhhdTGdW/6vhbT78xOfH68Zi3ayoen+ry4rXi6xcuvDG4LFTHxo6yAIBUP+jnWt0qjo6QQ3Qwjgq6qfzmJz/Ba1f+9Mo27Njhw3gNmrRoDlESSYZkyMr6p9eufYrXvvhiewm1Khu7tmfwGlg0W1K0iQYbYyAclXXjR7e+/T9//dYoXlM+Q03KlrKCbE//3U49ndo79j31MI5dnH48dLlcXipNDq3054p4ja+Ojy4kfogOnhKjao66jym8BvuAehx5tYGqFx32ysPSxWJeuvb21cnRbG9vdhSvsTNjQ7OU8sXDh+h4srOTU2tgapvYjG9AFKCB5njZ6dQd8HwcS+lMRkw5KYLjGNrksDspSs8W2ftfSh1ijgjxmNh+OJTjep4tdl2IHgj281ysO3qop5w9Z+mMn/BztC/gs4b3JcqJzEy6Izrrbgt4/X6Sdh0qZapdgCFa20Q/QFvgBgaAojkpnZG1cASvBXeQjMpPOZWRJZOawz8VJ1bXMRMJ9IelxGJ2/uSK2RgYfMLN2sZyAct0fmymJcS7HE/5wucuKj8TvcxFyjZtbve5KA27Qm0TO/FtsENAr5ghGFJ0EFowrTherZ+hVSKjUmjAZ7RcWjf6inRuJpGbn+EyRzoidsESCkr49rujHl/f74wefj6/Uh79g9j3rPs0XoRrm+g22gKPFoF7BKOOopjKyJTJhNyl84Wh54rxQW+JCUr5fKcrbsuyRyy9lw9OLfX6qXnfaKG/4mg5HmzT+87XNtEWvg02CO5gpTnmVZLuorTTrF9Vz/fMpyNdbtP6itnoKWMXb7W125lMwvLa85OX+7yu0b/ZHkh6mBW7+3vWfQODwyXAWu6foi1w1fHZCaIxLKSyQ83dIKbVKCgweHH/wJmewdmEESv3zeWklElyc29+wHfQGUvf0sHJpXx+sWhjGzNi6KjHj7IRKaHPmQsALeE76imSjCR/iWvqeJJP7t8fnhgIpFvbmj2WNv/Ro+jq2YY26UjaYjrT0BDi/JeUl1UtomsxTKAtSEAPjGjIcFJaBUIlk7RTAiU6mPqw0bzWB5VedpPJoE+MBpqtPj00p5n8KjvXNWhrC7o8keyc1BH65jjRmJ6RfQErHZmoPlW8MuLjeZ+P5yOpfp4V3SFLW+89T1dHTjA2C4G2VKvRWmzPjQuWxSba3j0SNrc4bdaeAXEyju5EI3xEECJRZT3sploNBpfb69OxKajN1jiqaRCxMwikliVBFtYJ74HU5PC6L+gVXPj2u0fd7Yuzyl0UyghuSnkfajWQAeCH+B7mIA0ABEjw6q5vP769q1myqOoG4Si8bvyLv/rbf3zrQh7fVs59+67y3/86+IJqX9tEVnwbWnTGkSK5S+B/H+1ZJxsbCJPVwlqOHcDM9n3KitDZBkKPY/ChLQhpcShR7+6eSojds6DOcDkpFWyhkeTEgXVfkO1U/yTQRn8g1i7QyZ3yOpX368cOTmirjlM9xuM4rZiNwcouUGgj74/twUnnu8adFmj7Ct91KagzAznz54vF8/n8uWLxXD4Wj8fisVh9VnuXpg5e7l2u9BdG1ZHVdWYIO9EW2MAPQD3KTqMfx1MO2yOZUfP0DfNPnsrNZ4I5T8M4lznSHrUL38LvJD3MH106vJJvc4//CQrvioxWO3odbYF1D7769OiVt41yDq/Z1exu9fba0cZ0KtnQ8JLRGEkpPwYEjtomegttAa/19ZHuc7ru7zpTVd+PHXbTveQz3H46Hwj5fXGPv0d49nD3dGC/J+3p7uaCvZFTFi5QdbdRNtJpM1vC3ZHSEd41Y3fyLve+JqY7PjCrc5usbaJzeEndXA00J0mMJMuitowfCSNUx4uj5AvLy4zP4jZTNtly+sids6bV1UvfjbIm46LJovvK1TbRb9CG2v893CTrcvifk8Pr/qCXc66vNBkCI5bFWZRWPpEiHh8aUlpLbIeuQ3gDbWg8NYiU06lCKcuP/Wdg6nckgrh25Y1Ok9lkJJob5Ze6GlsII9FIJP5w+d0Y0UwYiSaiA208YIc4boR5oJ1D7AOl9TtMWRDKzHe0nC21PrSNNlS2PcJdlh8PbdiHV5yhFg9hfYIVzMQ/XxtsspqNT5CNua+9S3WNf2QyXkANYZ8H/fRjuswyg8zHSlPf4frdgK1toof4FWiq81nvpcOuclm/L9HaGnWiJ05evXpS/bkFihLcLsHlEizfuHXr7bdv3frGRXZuerpK09Xp6TlWzbsMgP4Lv6jphrpupExGVsWp/Opyeog+s7yMzh8ze+3bW8t6b/wA6Gf4FfCq9n1YH6P6TtemQFU10cFOXi0nI7TsmkgsFPNzUk817co5f+9Q5eqzsUSS94ynxNSxXun8+Yyh4Yrq11nbRJ/gVyDyZd4y0s6w7twcHl1G/79ylin6ykKiyztSOtIvcLTsH+lYyC48L4vyYGHRkhJmvWE+7I04TyW4EOv3PMm1H5tKlp3G1kpfz1S7jm2kton+V8NWAEC0idgJbtiz5TWIid1xRza3aDd3hUKJhL/3XGn48kC+6q+0yl4myxjcw76Di9l5xProA93JTCqq/EfhtfPLN4ZjgRlrGzs9EmTmT+yfT2uYdgCgB/hFaAYQ+7AckkKOfQbiLRNdzik/RR/KA2yr8fQ7b05deXLguRf/eFa7p6v3q59rfeDVTVBXuEdb8XGYDF/egxyvcQUR+aez+Rjbma72TJ9OheL9XSe8fCTsi+YsbCedExzerKVjXMyOuIzeoVRmPDo/Hh90Gt1j+dREHP1urJONhVm+Q/mYF7ysj7RJvmgCMNC1TfRAwzMCYNNnV0PPttvZjKzp5R5Vfqcz7BZtZpkOdvbmZ/1jrRlvuDuM3cO+zOFU9nh3nwoy+vtUVMNUscT9OpSBcHR6YP9xsfDqhef+bBgQxGt9COA9VUMpPpPhaZp5bGBG/V1ZhI2YyWS4VLr60Zi9wLYLXHykcHAFQN2xvbVN+CX6P8xDBgAVwaSetZrud89zQetfO9xBIZQEA4AsiY72X985dUp//n30TdShPw852tGr35+bAwRDtQoS8Cdqvym9bZTWD+puvlTKV+VUSv7gmR+trv7oGe6p+4un7y8Ags5aBbXW3+G1iVeRdNhNa9WuVKqrmi+VPuAW7p9evP8Up70LCKZrp1AU/xsQ2qZyqPfh6XsnTtwwVMe2+8f0eY7XTiFUt9HmXyTjJ0/euzGG/2Vs6+u6DV97gPdjUv3GokiCRyIiePLz1XHUZESWiZc96OT1EnIqvyhdV95U7YXaL/EUblTtG3iVzryMHKi3fF25iU5cLyMnOb66tDqufGb8iv8GJFOkSMoUQinls/HVyy9PKJse5CxfRyeUm9fLyi/0HQk/QBsqrupdp7CONpRWQLX3cDdM4XvqNx75WMPZeJxl43HcHWWYqPpTY2o9hvdUW+ox2+ucKHKcKFokXpAkgZfgtwAAAP//AQAA///oy04cAAABAAAAAguF1euioV8PPPUAAQPoAAAAANhdoIQAAAAA3WYvNv43/sQIbQPxAAEAAwACAAAAAAAAAAEAAAPY/u8AAAiY/jf+NwhtAAEAAAAAAAAAAAAAAAAAAAA3eJwcyzFKA1EURuFz/4AoBLxCDKlSxJFo5hHsFMwrbiMWPrBQfBaWClmDhTtwEfY2tm7A3g24DpuEmeprztEXt/yA8uZfTxS9UjSk6IOiF4ruKHqmKHGkfRbKhP3SKDPXDo3dM9GYmS4JG3GuhrApMXgktCLU9m3YO2HfHNobB7pgNdhloj2Gco7lXMmZyhnLOZWT5CzkzCyxtETuvaG1P1qrXFvlzCoPVllqzVxrTjptRMDms3u2AAAA//8BAAD//5q1HWkAAAAAAAAsACwAUACEAKgAvADSAOwBDgE0AXQBrAHeAgoCPAJwApYC/gMgAywDRANgA5IDtAPgBBAEMARsBJIEtATsBRwFSAVgBYwFygYKBiQGcgayBtIG3gbqBvYHAgccBzYHSAdaB3IHigeiB64HxAfaAAEAAAA3AJAADABjAAcAAQAAAAAAAAAAAAAAAAAEAAN4nJyUz24bVRTGf05s0wrBAkVVuonugkWR6NhUSdU2K4fUikUUB48LQkJIE8/4jzKeGXkmDuEJWPMWvEVXPATPgVij+Xzs2AXRJoqSfHfu+fOdc75zgR3+ZptK9SHwRz0xXGGvfm54iwf1E8PbtOtbhqs8qf1puEZYmxuu83mtZ/gj3lZ/M/yA/epPhh+yW20b/phn1R3Dn2w7/jL8Kfu8XeAKvOBXwxV2yQxvscOPhrd5hMWsVHlE03CNz9gzXGcP6DOhIGZCwgjHkAkjrpgRkeMTMWPCkIgQR4cWMYW+JgRCjtF/fg3wKZgRKOKYAkeMT0xAztgi/iKvlHNlHOo0s7sWBWMCLuRxSUCCI2VESkLEpeIUFGS8okGDnIH4ZhTkeORMiPFImTGiQZc2p/QZMyHH0VakkplPypCCawLld2ZRdmZAREJurK5ICMXTiV8k7w6nOLpksl2PfLoR4Usc38m75JbK9is8/bo1Zpt5l2wC5upnrK7EurnWBMe6LfO2+Fa44BXuXv3ZZPL+HoX6XyjyBVeaf6hJJWKS4NwuLXwpyHePcRzp3MFXR76nQ58Turyhr3OLHj1anNGnw2v5dunh+JouZxzLoyO8uGtLMWf8gOMbOrIpY0fWn8XEIn4mM3Xn4jhTHVMy9bxk7qnWSBXefcLlDqUb6sjlM9AelZZO80u0ZwEjU0UmhlP1cqmN3PoXmiKmqqWc7e19uQ1z273lFt+QaodLtS44lZNbMHrfVL13NHOtH4+AkJQLWQxImdKg4Ea8zwm4IsZxrO6daEsKWiufMs+NVBIxFYMOieLMyPQ3MN34xn2woXtnb0ko/5Lp5aqq+2Rx6tXtjN6oe8s737ocrU2gYVNN19Q0ENfEtB9pp9b5+/LN9bqlPOWIlJjwXy/AMzya7HPAIWNlGOhmbq9DUy9Ek5ccqvpLIlkNpefIIhzg8ZwDDnjJ83f6uGTijItbcVnP3eKYI7ocflAVC/suR7xeffv/rL+LaVO1OJ6uTi/uPcUnd1DrF9qz2/eyp4mVk5hbtNutOCNgWnJxu+s1ucd4/wAAAP//AQAA///0t09ReJxiYGYAg//nGIwYsAAAAAAA//8BAAD//y8BAgMAAAA=&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-840467138 .fill-N1{fill:#0A0F25;}
		.d2-840467138 .fill-N2{fill:#676C7E;}
		.d2-840467138 .fill-N3{fill:#9499AB;}
		.d2-840467138 .fill-N4{fill:#CFD2DD;}
		.d2-840467138 .fill-N5{fill:#DEE1EB;}
		.d2-840467138 .fill-N6{fill:#EEF1F8;}
		.d2-840467138 .fill-N7{fill:#FFFFFF;}
		.d2-840467138 .fill-B1{fill:#0D32B2;}
		.d2-840467138 .fill-B2{fill:#0D32B2;}
		.d2-840467138 .fill-B3{fill:#E3E9FD;}
		.d2-840467138 .fill-B4{fill:#E3E9FD;}
		.d2-840467138 .fill-B5{fill:#EDF0FD;}
		.d2-840467138 .fill-B6{fill:#F7F8FE;}
		.d2-840467138 .fill-AA2{fill:#4A6FF3;}
		.d2-840467138 .fill-AA4{fill:#EDF0FD;}
		.d2-840467138 .fill-AA5{fill:#F7F8FE;}
		.d2-840467138 .fill-AB4{fill:#EDF0FD;}
		.d2-840467138 .fill-AB5{fill:#F7F8FE;}
		.d2-840467138 .stroke-N1{stroke:#0A0F25;}
		.d2-840467138 .stroke-N2{stroke:#676C7E;}
		.d2-840467138 .stroke-N3{stroke:#9499AB;}
		.d2-840467138 .stroke-N4{stroke:#CFD2DD;}
		.d2-840467138 .stroke-N5{stroke:#DEE1EB;}
		.d2-840467138 .stroke-N6{stroke:#EEF1F8;}
		.d2-840467138 .stroke-N7{stroke:#FFFFFF;}
		.d2-840467138 .stroke-B1{stroke:#0D32B2;}
		.d2-840467138 .stroke-B2{stroke:#0D32B2;}
		.d2-840467138 .stroke-B3{stroke:#E3E9FD;}
		.d2-840467138 .stroke-B4{stroke:#E3E9FD;}
		.d2-840467138 .stroke-B5{stroke:#EDF0FD;}
		.d2-840467138 .stroke-B6{stroke:#F7F8FE;}
		.d2-840467138 .stroke-AA2{stroke:#4A6FF3;}
		.d2-840467138 .stroke-AA4{stroke:#EDF0FD;}
		.d2-840467138 .stroke-AA5{stroke:#F7F8FE;}
		.d2-840467138 .stroke-AB4{stroke:#EDF0FD;}
		.d2-840467138 .stroke-AB5{stroke:#F7F8FE;}
		.d2-840467138 .background-color-N1{background-color:#0A0F25;}
		.d2-840467138 .background-color-N2{background-color:#676C7E;}
		.d2-840467138 .background-color-N3{background-color:#9499AB;}
		.d2-840467138 .background-color-N4{background-color:#CFD2DD;}
		.d2-840467138 .background-color-N5{background-color:#DEE1EB;}
		.d2-840467138 .background-color-N6{background-color:#EEF1F8;}
		.d2-840467138 .background-color-N7{background-color:#FFFFFF;}
		.d2-840467138 .background-color-B1{background-color:#0D32B2;}
		.d2-840467138 .background-color-B2{background-color:#0D32B2;}
		.d2-840467138 .background-color-B3{background-color:#E3E9FD;}
		.d2-840467138 .background-color-B4{background-color:#E3E9FD;}
		.d2-840467138 .background-color-B5{background-color:#EDF0FD;}
		.d2-840467138 .background-color-B6{background-color:#F7F8FE;}
		.d2-840467138 .background-color-AA2{background-color:#4A6FF3;}
		.d2-840467138 .background-color-AA4{background-color:#EDF0FD;}
		.d2-840467138 .background-color-AA5{background-color:#F7F8FE;}
		.d2-840467138 .background-color-AB4{background-color:#EDF0FD;}
		.d2-840467138 .background-color-AB5{background-color:#F7F8FE;}
		.d2-840467138 .color-N1{color:#0A0F25;}
		.d2-840467138 .color-N2{color:#676C7E;}
		.d2-840467138 .color-N3{color:#9499AB;}
		.d2-840467138 .color-N4{color:#CFD2DD;}
		.d2-840467138 .color-N5{color:#DEE1EB;}
		.d2-840467138 .color-N6{color:#EEF1F8;}
		.d2-840467138 .color-N7{color:#FFFFFF;}
		.d2-840467138 .color-B1{color:#0D32B2;}
		.d2-840467138 .color-B2{color:#0D32B2;}
		.d2-840467138 .color-B3{color:#E3E9FD;}
		.d2-840467138 .color-B4{color:#E3E9FD;}
		.d2-840467138 .color-B5{color:#EDF0FD;}
		.d2-840467138 .color-B6{color:#F7F8FE;}
		.d2-840467138 .color-AA2{color:#4A6FF3;}
		.d2-840467138 .color-AA4{color:#EDF0FD;}
		.d2-840467138 .color-AA5{color:#F7F8FE;}
		.d2-840467138 .color-AB4{color:#EDF0FD;}
		.d2-840467138 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-840467138);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-840467138);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-840467138);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-840467138);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-840467138);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-840467138);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-840467138);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-840467138);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-840467138);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-840467138);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-840467138);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-840467138);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-840467138);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-840467138);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-840467138);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-840467138);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-840467138);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-840467138);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;cGFnZQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;10.000000&quot; y=&quot;20.000000&quot; width=&quot;1988.000000&quot; height=&quot;142.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#E3E9FD&quot; class=&quot;stroke-B1 fill-B4&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;1004.000000&quot; y=&quot;7.000000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:28px&quot;&gt;Database Page (typically 8–16 KB)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;cGFnZS5oZWFkZXI=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;40.000000&quot; y=&quot;50.000000&quot; width=&quot;365.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;222.500000&quot; y=&quot;88.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;222.500000&quot; dy=&quot;0.000000&quot;&gt;Page Header&lt;/tspan&gt;&lt;tspan x=&quot;222.500000&quot; dy=&quot;18.500000&quot;&gt;(page number, free-space pointer, checksum)&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;cGFnZS5zbG90cw==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;465.000000&quot; y=&quot;58.000000&quot; width=&quot;549.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;739.500000&quot; y=&quot;96.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Slot Array →  [slot 1: offset 7200] [slot 2: offset 6900] [slot 3: offset 6600]&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;cGFnZS5mcmVl&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;1074.000000&quot; y=&quot;50.000000&quot; width=&quot;348.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;1248.000000&quot; y=&quot;88.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;1248.000000&quot; dy=&quot;0.000000&quot;&gt;Free Space&lt;/tspan&gt;&lt;tspan x=&quot;1248.000000&quot; dy=&quot;18.500000&quot;&gt;(slot array grows down ↓ ; rows grow up ↑)&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;cGFnZS5yMw==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;1482.000000&quot; y=&quot;58.000000&quot; width=&quot;122.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;1543.000000&quot; y=&quot;96.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Row 3 data&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;cGFnZS5yMg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;1664.000000&quot; y=&quot;58.000000&quot; width=&quot;122.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;1725.000000&quot; y=&quot;96.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Row 2 data&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;cGFnZS5yMQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;1846.000000&quot; y=&quot;58.000000&quot; width=&quot;122.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;1907.000000&quot; y=&quot;96.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Row 1 data&lt;/text&gt;&lt;/g&gt;&lt;mask id=&quot;d2-840467138&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-15&quot; y=&quot;-45&quot; width=&quot;2038&quot; height=&quot;232&quot;&gt;
&lt;rect x=&quot;-15&quot; y=&quot;-45&quot; width=&quot;2038&quot; height=&quot;232&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;

&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;Rows are written from the bottom of the page upward. The slot array at the top grows downward. This design means rows can be moved within a page (for compaction) without changing the slot number — callers reference &lt;code&gt;(page, slot)&lt;/code&gt;, not a raw byte offset.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt; If your query touches 1 row that happens to share a page with 99 other rows, the database reads all 100 rows’ worth of data into memory regardless. Page size is why “one row lookups” are cheap only when paired with an index — without one, you may read every page in the table.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-heap-an-unordered-table&quot;&gt;The Heap: An Unordered Table&lt;/h2&gt;
&lt;p&gt;The default table structure in most databases is a &lt;strong&gt;heap&lt;/strong&gt;. A heap is simply a collection of pages with no inherent ordering — rows are inserted wherever there is free space, not in any sorted order.&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 653 264&quot;&gt;&lt;svg class=&quot;d2-3480569638 d2-svg&quot; width=&quot;653&quot; height=&quot;264&quot; viewBox=&quot;-5 -9 653 264&quot;&gt;&lt;rect x=&quot;-5.000000&quot; y=&quot;-9.000000&quot; width=&quot;653.000000&quot; height=&quot;264.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-3480569638 .text {
	font-family: &quot;d2-3480569638-font-regular&quot;;
}
@font-face {
	font-family: d2-3480569638-font-regular;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-3480569638 .text-bold {
	font-family: &quot;d2-3480569638-font-bold&quot;;
}
@font-face {
	font-family: d2-3480569638-font-bold;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-3480569638 .fill-N1{fill:#0A0F25;}
		.d2-3480569638 .fill-N2{fill:#676C7E;}
		.d2-3480569638 .fill-N3{fill:#9499AB;}
		.d2-3480569638 .fill-N4{fill:#CFD2DD;}
		.d2-3480569638 .fill-N5{fill:#DEE1EB;}
		.d2-3480569638 .fill-N6{fill:#EEF1F8;}
		.d2-3480569638 .fill-N7{fill:#FFFFFF;}
		.d2-3480569638 .fill-B1{fill:#0D32B2;}
		.d2-3480569638 .fill-B2{fill:#0D32B2;}
		.d2-3480569638 .fill-B3{fill:#E3E9FD;}
		.d2-3480569638 .fill-B4{fill:#E3E9FD;}
		.d2-3480569638 .fill-B5{fill:#EDF0FD;}
		.d2-3480569638 .fill-B6{fill:#F7F8FE;}
		.d2-3480569638 .fill-AA2{fill:#4A6FF3;}
		.d2-3480569638 .fill-AA4{fill:#EDF0FD;}
		.d2-3480569638 .fill-AA5{fill:#F7F8FE;}
		.d2-3480569638 .fill-AB4{fill:#EDF0FD;}
		.d2-3480569638 .fill-AB5{fill:#F7F8FE;}
		.d2-3480569638 .stroke-N1{stroke:#0A0F25;}
		.d2-3480569638 .stroke-N2{stroke:#676C7E;}
		.d2-3480569638 .stroke-N3{stroke:#9499AB;}
		.d2-3480569638 .stroke-N4{stroke:#CFD2DD;}
		.d2-3480569638 .stroke-N5{stroke:#DEE1EB;}
		.d2-3480569638 .stroke-N6{stroke:#EEF1F8;}
		.d2-3480569638 .stroke-N7{stroke:#FFFFFF;}
		.d2-3480569638 .stroke-B1{stroke:#0D32B2;}
		.d2-3480569638 .stroke-B2{stroke:#0D32B2;}
		.d2-3480569638 .stroke-B3{stroke:#E3E9FD;}
		.d2-3480569638 .stroke-B4{stroke:#E3E9FD;}
		.d2-3480569638 .stroke-B5{stroke:#EDF0FD;}
		.d2-3480569638 .stroke-B6{stroke:#F7F8FE;}
		.d2-3480569638 .stroke-AA2{stroke:#4A6FF3;}
		.d2-3480569638 .stroke-AA4{stroke:#EDF0FD;}
		.d2-3480569638 .stroke-AA5{stroke:#F7F8FE;}
		.d2-3480569638 .stroke-AB4{stroke:#EDF0FD;}
		.d2-3480569638 .stroke-AB5{stroke:#F7F8FE;}
		.d2-3480569638 .background-color-N1{background-color:#0A0F25;}
		.d2-3480569638 .background-color-N2{background-color:#676C7E;}
		.d2-3480569638 .background-color-N3{background-color:#9499AB;}
		.d2-3480569638 .background-color-N4{background-color:#CFD2DD;}
		.d2-3480569638 .background-color-N5{background-color:#DEE1EB;}
		.d2-3480569638 .background-color-N6{background-color:#EEF1F8;}
		.d2-3480569638 .background-color-N7{background-color:#FFFFFF;}
		.d2-3480569638 .background-color-B1{background-color:#0D32B2;}
		.d2-3480569638 .background-color-B2{background-color:#0D32B2;}
		.d2-3480569638 .background-color-B3{background-color:#E3E9FD;}
		.d2-3480569638 .background-color-B4{background-color:#E3E9FD;}
		.d2-3480569638 .background-color-B5{background-color:#EDF0FD;}
		.d2-3480569638 .background-color-B6{background-color:#F7F8FE;}
		.d2-3480569638 .background-color-AA2{background-color:#4A6FF3;}
		.d2-3480569638 .background-color-AA4{background-color:#EDF0FD;}
		.d2-3480569638 .background-color-AA5{background-color:#F7F8FE;}
		.d2-3480569638 .background-color-AB4{background-color:#EDF0FD;}
		.d2-3480569638 .background-color-AB5{background-color:#F7F8FE;}
		.d2-3480569638 .color-N1{color:#0A0F25;}
		.d2-3480569638 .color-N2{color:#676C7E;}
		.d2-3480569638 .color-N3{color:#9499AB;}
		.d2-3480569638 .color-N4{color:#CFD2DD;}
		.d2-3480569638 .color-N5{color:#DEE1EB;}
		.d2-3480569638 .color-N6{color:#EEF1F8;}
		.d2-3480569638 .color-N7{color:#FFFFFF;}
		.d2-3480569638 .color-B1{color:#0D32B2;}
		.d2-3480569638 .color-B2{color:#0D32B2;}
		.d2-3480569638 .color-B3{color:#E3E9FD;}
		.d2-3480569638 .color-B4{color:#E3E9FD;}
		.d2-3480569638 .color-B5{color:#EDF0FD;}
		.d2-3480569638 .color-B6{color:#F7F8FE;}
		.d2-3480569638 .color-AA2{color:#4A6FF3;}
		.d2-3480569638 .color-AA4{color:#EDF0FD;}
		.d2-3480569638 .color-AA5{color:#F7F8FE;}
		.d2-3480569638 .color-AB4{color:#EDF0FD;}
		.d2-3480569638 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-3480569638);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-3480569638);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-3480569638);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-3480569638);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-3480569638);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-3480569638);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-3480569638);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-3480569638);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-3480569638);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-3480569638);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-3480569638);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-3480569638);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-3480569638);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-3480569638);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-3480569638);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-3480569638);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-3480569638);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-3480569638);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;SGVhcFRhYmxl&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;20.000000&quot; y=&quot;56.000000&quot; width=&quot;603.000000&quot; height=&quot;174.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#E3E9FD&quot; class=&quot;stroke-B1 fill-B4&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;321.500000&quot; y=&quot;43.000000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:28px&quot;&gt;Heap Table&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;SGVhcFRhYmxlLlAx&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;50.000000&quot; y=&quot;86.000000&quot; width=&quot;114.000000&quot; height=&quot;114.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;107.000000&quot; y=&quot;124.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;107.000000&quot; dy=&quot;0.000000&quot;&gt;Page 1&lt;/tspan&gt;&lt;tspan x=&quot;107.000000&quot; dy=&quot;17.250000&quot;&gt;Row: id=5&lt;/tspan&gt;&lt;tspan x=&quot;107.000000&quot; dy=&quot;17.250000&quot;&gt;Row: id=1&lt;/tspan&gt;&lt;tspan x=&quot;107.000000&quot; dy=&quot;17.250000&quot;&gt;Row: id=9&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;SGVhcFRhYmxlLlAy&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;264.000000&quot; y=&quot;86.000000&quot; width=&quot;114.000000&quot; height=&quot;114.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;321.000000&quot; y=&quot;124.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;321.000000&quot; dy=&quot;0.000000&quot;&gt;Page 2&lt;/tspan&gt;&lt;tspan x=&quot;321.000000&quot; dy=&quot;17.250000&quot;&gt;Row: id=3&lt;/tspan&gt;&lt;tspan x=&quot;321.000000&quot; dy=&quot;17.250000&quot;&gt;Row: id=7&lt;/tspan&gt;&lt;tspan x=&quot;321.000000&quot; dy=&quot;17.250000&quot;&gt;Row: id=2&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;SGVhcFRhYmxlLlAz&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;478.000000&quot; y=&quot;86.000000&quot; width=&quot;115.000000&quot; height=&quot;114.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;535.500000&quot; y=&quot;124.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;535.500000&quot; dy=&quot;0.000000&quot;&gt;Page 3&lt;/tspan&gt;&lt;tspan x=&quot;535.500000&quot; dy=&quot;17.250000&quot;&gt;Row: id=8&lt;/tspan&gt;&lt;tspan x=&quot;535.500000&quot; dy=&quot;17.250000&quot;&gt;Row: id=4&lt;/tspan&gt;&lt;tspan x=&quot;535.500000&quot; dy=&quot;17.250000&quot;&gt;Row: id=6&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;SGVhcFRhYmxlLihQMSAtJmd0OyBQMilbMF0=&quot;&gt;&lt;marker id=&quot;mk-d2-3480569638-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 166.000000 143.000000 C 204.000000 143.000000 224.000000 143.000000 260.000000 143.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3480569638-3488378134)&quot; mask=&quot;url(#d2-3480569638)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;SGVhcFRhYmxlLihQMiAtJmd0OyBQMylbMF0=&quot;&gt;&lt;path d=&quot;M 380.000000 143.000000 C 418.000000 143.000000 438.000000 143.000000 474.000000 143.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3480569638-3488378134)&quot; mask=&quot;url(#d2-3480569638)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;mask id=&quot;d2-3480569638&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-5&quot; y=&quot;-9&quot; width=&quot;653&quot; height=&quot;264&quot;&gt;
&lt;rect x=&quot;-5&quot; y=&quot;-9&quot; width=&quot;653&quot; height=&quot;264&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;

&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;Notice: the rows are in no particular order. &lt;code&gt;id=1&lt;/code&gt; is on page 1, &lt;code&gt;id=2&lt;/code&gt; is on page 2, &lt;code&gt;id=3&lt;/code&gt; is on page 2. There is no relationship between the key value and where the row physically lives.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Consequence:&lt;/strong&gt; To find &lt;code&gt;id = 4&lt;/code&gt; without an index, the database must read every page from start to finish — a &lt;strong&gt;sequential scan&lt;/strong&gt; or &lt;strong&gt;full table scan&lt;/strong&gt;. For a 10-million-row table, that means reading millions of pages from disk.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;row-ids-the-physical-address-of-a-row&quot;&gt;Row IDs: The Physical Address of a Row&lt;/h2&gt;
&lt;p&gt;Every row in a heap has a physical address — a pointer to exactly which page and which slot it occupies. Different databases name this differently:&lt;/p&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;PostgreSQL&lt;/th&gt;&lt;th&gt;Oracle&lt;/th&gt;&lt;th&gt;SQL Server&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;ctid&lt;/td&gt;&lt;td&gt;ROWID&lt;/td&gt;&lt;td&gt;RID&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;e.g. (2, 3)&lt;/td&gt;&lt;td&gt;e.g. AAABXSAABAAAACFAAH&lt;/td&gt;&lt;td&gt;e.g. 1:2:3&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;= page 2, slot 3&lt;/td&gt;&lt;td&gt;encoded page + slot&lt;/td&gt;&lt;td&gt;= file 1, page 2, slot 3&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;These row IDs are &lt;strong&gt;physical, not logical&lt;/strong&gt;. They change when a row is moved — during &lt;code&gt;VACUUM FULL&lt;/code&gt; (&lt;code&gt;VACUUM&lt;/code&gt; is PostgreSQL’s process for reclaiming space from deleted/updated row versions), &lt;code&gt;CLUSTER&lt;/code&gt;, or other operations that physically rewrite tuples. Standard &lt;code&gt;VACUUM&lt;/code&gt; does &lt;em&gt;not&lt;/em&gt; move existing tuples and does not change ctids. This has critical implications for how indexes work, as we’ll see next.&lt;/p&gt;
&lt;p&gt;Row IDs are not normally exposed to application code, but they are the mechanism that makes indexes fast.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;indexes-and-how-they-use-row-ids&quot;&gt;Indexes and How They Use Row IDs&lt;/h2&gt;
&lt;p&gt;An &lt;strong&gt;index&lt;/strong&gt; is a separate data structure — almost always a &lt;a href=&quot;/blog/btrees-and-bplus-trees/&quot;&gt;B-tree or B+ tree&lt;/a&gt; — that maps a column’s values to the physical location of the corresponding rows in the heap.&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 950 749&quot;&gt;&lt;svg class=&quot;d2-156336119 d2-svg&quot; width=&quot;950&quot; height=&quot;749&quot; viewBox=&quot;-15 -45 950 749&quot;&gt;&lt;rect x=&quot;-15.000000&quot; y=&quot;-45.000000&quot; width=&quot;950.000000&quot; height=&quot;749.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-156336119 .text {
	font-family: &quot;d2-156336119-font-regular&quot;;
}
@font-face {
	font-family: d2-156336119-font-regular;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-156336119 .text-bold {
	font-family: &quot;d2-156336119-font-bold&quot;;
}
@font-face {
	font-family: d2-156336119-font-bold;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-156336119 .text-italic {
	font-family: &quot;d2-156336119-font-italic&quot;;
}
@font-face {
	font-family: d2-156336119-font-italic;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-156336119 .fill-N1{fill:#0A0F25;}
		.d2-156336119 .fill-N2{fill:#676C7E;}
		.d2-156336119 .fill-N3{fill:#9499AB;}
		.d2-156336119 .fill-N4{fill:#CFD2DD;}
		.d2-156336119 .fill-N5{fill:#DEE1EB;}
		.d2-156336119 .fill-N6{fill:#EEF1F8;}
		.d2-156336119 .fill-N7{fill:#FFFFFF;}
		.d2-156336119 .fill-B1{fill:#0D32B2;}
		.d2-156336119 .fill-B2{fill:#0D32B2;}
		.d2-156336119 .fill-B3{fill:#E3E9FD;}
		.d2-156336119 .fill-B4{fill:#E3E9FD;}
		.d2-156336119 .fill-B5{fill:#EDF0FD;}
		.d2-156336119 .fill-B6{fill:#F7F8FE;}
		.d2-156336119 .fill-AA2{fill:#4A6FF3;}
		.d2-156336119 .fill-AA4{fill:#EDF0FD;}
		.d2-156336119 .fill-AA5{fill:#F7F8FE;}
		.d2-156336119 .fill-AB4{fill:#EDF0FD;}
		.d2-156336119 .fill-AB5{fill:#F7F8FE;}
		.d2-156336119 .stroke-N1{stroke:#0A0F25;}
		.d2-156336119 .stroke-N2{stroke:#676C7E;}
		.d2-156336119 .stroke-N3{stroke:#9499AB;}
		.d2-156336119 .stroke-N4{stroke:#CFD2DD;}
		.d2-156336119 .stroke-N5{stroke:#DEE1EB;}
		.d2-156336119 .stroke-N6{stroke:#EEF1F8;}
		.d2-156336119 .stroke-N7{stroke:#FFFFFF;}
		.d2-156336119 .stroke-B1{stroke:#0D32B2;}
		.d2-156336119 .stroke-B2{stroke:#0D32B2;}
		.d2-156336119 .stroke-B3{stroke:#E3E9FD;}
		.d2-156336119 .stroke-B4{stroke:#E3E9FD;}
		.d2-156336119 .stroke-B5{stroke:#EDF0FD;}
		.d2-156336119 .stroke-B6{stroke:#F7F8FE;}
		.d2-156336119 .stroke-AA2{stroke:#4A6FF3;}
		.d2-156336119 .stroke-AA4{stroke:#EDF0FD;}
		.d2-156336119 .stroke-AA5{stroke:#F7F8FE;}
		.d2-156336119 .stroke-AB4{stroke:#EDF0FD;}
		.d2-156336119 .stroke-AB5{stroke:#F7F8FE;}
		.d2-156336119 .background-color-N1{background-color:#0A0F25;}
		.d2-156336119 .background-color-N2{background-color:#676C7E;}
		.d2-156336119 .background-color-N3{background-color:#9499AB;}
		.d2-156336119 .background-color-N4{background-color:#CFD2DD;}
		.d2-156336119 .background-color-N5{background-color:#DEE1EB;}
		.d2-156336119 .background-color-N6{background-color:#EEF1F8;}
		.d2-156336119 .background-color-N7{background-color:#FFFFFF;}
		.d2-156336119 .background-color-B1{background-color:#0D32B2;}
		.d2-156336119 .background-color-B2{background-color:#0D32B2;}
		.d2-156336119 .background-color-B3{background-color:#E3E9FD;}
		.d2-156336119 .background-color-B4{background-color:#E3E9FD;}
		.d2-156336119 .background-color-B5{background-color:#EDF0FD;}
		.d2-156336119 .background-color-B6{background-color:#F7F8FE;}
		.d2-156336119 .background-color-AA2{background-color:#4A6FF3;}
		.d2-156336119 .background-color-AA4{background-color:#EDF0FD;}
		.d2-156336119 .background-color-AA5{background-color:#F7F8FE;}
		.d2-156336119 .background-color-AB4{background-color:#EDF0FD;}
		.d2-156336119 .background-color-AB5{background-color:#F7F8FE;}
		.d2-156336119 .color-N1{color:#0A0F25;}
		.d2-156336119 .color-N2{color:#676C7E;}
		.d2-156336119 .color-N3{color:#9499AB;}
		.d2-156336119 .color-N4{color:#CFD2DD;}
		.d2-156336119 .color-N5{color:#DEE1EB;}
		.d2-156336119 .color-N6{color:#EEF1F8;}
		.d2-156336119 .color-N7{color:#FFFFFF;}
		.d2-156336119 .color-B1{color:#0D32B2;}
		.d2-156336119 .color-B2{color:#0D32B2;}
		.d2-156336119 .color-B3{color:#E3E9FD;}
		.d2-156336119 .color-B4{color:#E3E9FD;}
		.d2-156336119 .color-B5{color:#EDF0FD;}
		.d2-156336119 .color-B6{color:#F7F8FE;}
		.d2-156336119 .color-AA2{color:#4A6FF3;}
		.d2-156336119 .color-AA4{color:#EDF0FD;}
		.d2-156336119 .color-AA5{color:#F7F8FE;}
		.d2-156336119 .color-AB4{color:#EDF0FD;}
		.d2-156336119 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-156336119);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-156336119);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-156336119);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-156336119);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-156336119);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-156336119);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-156336119);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-156336119);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-156336119);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-156336119);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-156336119);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-156336119);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-156336119);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-156336119);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-156336119);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-156336119);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-156336119);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-156336119);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;QlRyZWU=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;10.000000&quot; y=&quot;20.000000&quot; width=&quot;900.000000&quot; height=&quot;324.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#E3E9FD&quot; class=&quot;stroke-B1 fill-B4&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;460.000000&quot; y=&quot;7.000000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:28px&quot;&gt;B-Tree Index on id&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;SGVhcA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;68.000000&quot; y=&quot;505.000000&quot; width=&quot;785.000000&quot; height=&quot;174.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#E3E9FD&quot; class=&quot;stroke-B1 fill-B4&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;460.500000&quot; y=&quot;492.000000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:28px&quot;&gt;Heap Pages&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;QlRyZWUuUm9vdA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;401.000000&quot; y=&quot;50.000000&quot; width=&quot;118.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;460.000000&quot; y=&quot;88.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;460.000000&quot; dy=&quot;0.000000&quot;&gt;Root Node&lt;/tspan&gt;&lt;tspan x=&quot;460.000000&quot; dy=&quot;18.500000&quot;&gt;[4 | 7]&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;QlRyZWUuTA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;40.000000&quot; y=&quot;232.000000&quot; width=&quot;240.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;160.000000&quot; y=&quot;270.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;160.000000&quot; dy=&quot;0.000000&quot;&gt;Leaf Node&lt;/tspan&gt;&lt;tspan x=&quot;160.000000&quot; dy=&quot;18.500000&quot;&gt;[1→(1,2)] [2→(2,3)] [3→(2,1)]&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;QlRyZWUuTQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;640.000000&quot; y=&quot;232.000000&quot; width=&quot;240.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;760.000000&quot; y=&quot;270.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;760.000000&quot; dy=&quot;0.000000&quot;&gt;Leaf Node&lt;/tspan&gt;&lt;tspan x=&quot;760.000000&quot; dy=&quot;18.500000&quot;&gt;[4→(3,2)] [5→(1,1)] [6→(3,3)]&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;QlRyZWUuUg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;340.000000&quot; y=&quot;232.000000&quot; width=&quot;240.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;460.000000&quot; y=&quot;270.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;460.000000&quot; dy=&quot;0.000000&quot;&gt;Leaf Node&lt;/tspan&gt;&lt;tspan x=&quot;460.000000&quot; dy=&quot;18.500000&quot;&gt;[7→(2,2)] [8→(3,1)] [9→(1,3)]&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;SGVhcC5QMQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;98.000000&quot; y=&quot;535.000000&quot; width=&quot;124.000000&quot; height=&quot;114.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;160.000000&quot; y=&quot;573.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;160.000000&quot; dy=&quot;0.000000&quot;&gt;Page 1&lt;/tspan&gt;&lt;tspan x=&quot;160.000000&quot; dy=&quot;17.250000&quot;&gt;Slot 1: id=5&lt;/tspan&gt;&lt;tspan x=&quot;160.000000&quot; dy=&quot;17.250000&quot;&gt;Slot 2: id=1&lt;/tspan&gt;&lt;tspan x=&quot;160.000000&quot; dy=&quot;17.250000&quot;&gt;Slot 3: id=9&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;SGVhcC5QMg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;398.000000&quot; y=&quot;535.000000&quot; width=&quot;124.000000&quot; height=&quot;114.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;460.000000&quot; y=&quot;573.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;460.000000&quot; dy=&quot;0.000000&quot;&gt;Page 2&lt;/tspan&gt;&lt;tspan x=&quot;460.000000&quot; dy=&quot;17.250000&quot;&gt;Slot 1: id=3&lt;/tspan&gt;&lt;tspan x=&quot;460.000000&quot; dy=&quot;17.250000&quot;&gt;Slot 2: id=7&lt;/tspan&gt;&lt;tspan x=&quot;460.000000&quot; dy=&quot;17.250000&quot;&gt;Slot 3: id=2&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;SGVhcC5QMw==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;698.000000&quot; y=&quot;535.000000&quot; width=&quot;125.000000&quot; height=&quot;114.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;760.500000&quot; y=&quot;573.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;760.500000&quot; dy=&quot;0.000000&quot;&gt;Page 3&lt;/tspan&gt;&lt;tspan x=&quot;760.500000&quot; dy=&quot;17.250000&quot;&gt;Slot 1: id=8&lt;/tspan&gt;&lt;tspan x=&quot;760.500000&quot; dy=&quot;17.250000&quot;&gt;Slot 2: id=4&lt;/tspan&gt;&lt;tspan x=&quot;760.500000&quot; dy=&quot;17.250000&quot;&gt;Slot 3: id=6&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;QlRyZWUuKFJvb3QgLSZndDsgTClbMF0=&quot;&gt;&lt;marker id=&quot;mk-d2-156336119-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 399.085884 109.579794 C 208.199997 167.399994 160.000000 192.000000 160.000000 228.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-156336119-3488378134)&quot; mask=&quot;url(#d2-156336119)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;QlRyZWUuKFJvb3QgLSZndDsgTSlbMF0=&quot;&gt;&lt;path d=&quot;M 520.914116 109.579794 C 711.799988 167.399994 760.000000 192.000000 760.000000 228.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-156336119-3488378134)&quot; mask=&quot;url(#d2-156336119)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;QlRyZWUuKFJvb3QgLSZndDsgUilbMF0=&quot;&gt;&lt;path d=&quot;M 460.000000 134.000000 C 460.000000 172.000000 460.000000 192.000000 460.000000 228.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-156336119-3488378134)&quot; mask=&quot;url(#d2-156336119)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEJUcmVlLkwgLSZndDsgSGVhcC5QMSlbMF0=&quot;&gt;&lt;path d=&quot;M 160.000000 316.000000 C 160.000000 354.000000 160.000000 376.100006 160.000000 394.250000 C 160.000000 412.399994 160.000000 495.000000 160.000000 531.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-156336119-3488378134)&quot; mask=&quot;url(#d2-156336119)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;160.500000&quot; y=&quot;430.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;(1,2)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEJUcmVlLk0gLSZndDsgSGVhcC5QMylbMF0=&quot;&gt;&lt;path d=&quot;M 760.000000 316.000000 C 760.000000 354.000000 760.000000 376.100006 760.000000 394.250000 C 760.000000 412.399994 760.000000 495.000000 760.000000 531.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-156336119-3488378134)&quot; mask=&quot;url(#d2-156336119)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;760.500000&quot; y=&quot;430.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;(3,2)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEJUcmVlLlIgLSZndDsgSGVhcC5QMilbMF0=&quot;&gt;&lt;path d=&quot;M 460.000000 316.000000 C 460.000000 354.000000 460.000000 376.100006 460.000000 394.250000 C 460.000000 412.399994 460.000000 495.000000 460.000000 531.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-156336119-3488378134)&quot; mask=&quot;url(#d2-156336119)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;460.500000&quot; y=&quot;430.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;(2,2)&lt;/text&gt;&lt;/g&gt;&lt;mask id=&quot;d2-156336119&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-15&quot; y=&quot;-45&quot; width=&quot;950&quot; height=&quot;749&quot;&gt;
&lt;rect x=&quot;-15&quot; y=&quot;-45&quot; width=&quot;950&quot; height=&quot;749&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;145.000000&quot; y=&quot;414.000000&quot; width=&quot;31&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;745.000000&quot; y=&quot;414.000000&quot; width=&quot;31&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;445.000000&quot; y=&quot;414.000000&quot; width=&quot;31&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;When you query &lt;code&gt;WHERE id = 7&lt;/code&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The database traverses the B-tree from root to leaf — typically 2–4 page reads for a large index.&lt;/li&gt;
&lt;li&gt;The leaf node contains the row ID: &lt;code&gt;(2, 2)&lt;/code&gt; — page 2, slot 2.&lt;/li&gt;
&lt;li&gt;The database reads page 2 from the heap and extracts the row at slot 2.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is a &lt;strong&gt;double lookup&lt;/strong&gt;: index traversal, then a heap fetch. For a single row, this is very fast. At scale, it’s the foundation of every indexed query plan.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-clustered-index-data-ordered-by-the-index&quot;&gt;The Clustered Index: Data Ordered by the Index&lt;/h2&gt;
&lt;p&gt;A &lt;strong&gt;clustered index&lt;/strong&gt; eliminates the double lookup by storing the actual row data inside the B-tree leaf nodes — not a pointer to a heap, but the row itself.&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 743 446&quot;&gt;&lt;svg class=&quot;d2-4060553005 d2-svg&quot; width=&quot;743&quot; height=&quot;446&quot; viewBox=&quot;-15 -45 743 446&quot;&gt;&lt;rect x=&quot;-15.000000&quot; y=&quot;-45.000000&quot; width=&quot;743.000000&quot; height=&quot;446.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-4060553005 .text {
	font-family: &quot;d2-4060553005-font-regular&quot;;
}
@font-face {
	font-family: d2-4060553005-font-regular;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-4060553005 .text-bold {
	font-family: &quot;d2-4060553005-font-bold&quot;;
}
@font-face {
	font-family: d2-4060553005-font-bold;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-4060553005 .fill-N1{fill:#0A0F25;}
		.d2-4060553005 .fill-N2{fill:#676C7E;}
		.d2-4060553005 .fill-N3{fill:#9499AB;}
		.d2-4060553005 .fill-N4{fill:#CFD2DD;}
		.d2-4060553005 .fill-N5{fill:#DEE1EB;}
		.d2-4060553005 .fill-N6{fill:#EEF1F8;}
		.d2-4060553005 .fill-N7{fill:#FFFFFF;}
		.d2-4060553005 .fill-B1{fill:#0D32B2;}
		.d2-4060553005 .fill-B2{fill:#0D32B2;}
		.d2-4060553005 .fill-B3{fill:#E3E9FD;}
		.d2-4060553005 .fill-B4{fill:#E3E9FD;}
		.d2-4060553005 .fill-B5{fill:#EDF0FD;}
		.d2-4060553005 .fill-B6{fill:#F7F8FE;}
		.d2-4060553005 .fill-AA2{fill:#4A6FF3;}
		.d2-4060553005 .fill-AA4{fill:#EDF0FD;}
		.d2-4060553005 .fill-AA5{fill:#F7F8FE;}
		.d2-4060553005 .fill-AB4{fill:#EDF0FD;}
		.d2-4060553005 .fill-AB5{fill:#F7F8FE;}
		.d2-4060553005 .stroke-N1{stroke:#0A0F25;}
		.d2-4060553005 .stroke-N2{stroke:#676C7E;}
		.d2-4060553005 .stroke-N3{stroke:#9499AB;}
		.d2-4060553005 .stroke-N4{stroke:#CFD2DD;}
		.d2-4060553005 .stroke-N5{stroke:#DEE1EB;}
		.d2-4060553005 .stroke-N6{stroke:#EEF1F8;}
		.d2-4060553005 .stroke-N7{stroke:#FFFFFF;}
		.d2-4060553005 .stroke-B1{stroke:#0D32B2;}
		.d2-4060553005 .stroke-B2{stroke:#0D32B2;}
		.d2-4060553005 .stroke-B3{stroke:#E3E9FD;}
		.d2-4060553005 .stroke-B4{stroke:#E3E9FD;}
		.d2-4060553005 .stroke-B5{stroke:#EDF0FD;}
		.d2-4060553005 .stroke-B6{stroke:#F7F8FE;}
		.d2-4060553005 .stroke-AA2{stroke:#4A6FF3;}
		.d2-4060553005 .stroke-AA4{stroke:#EDF0FD;}
		.d2-4060553005 .stroke-AA5{stroke:#F7F8FE;}
		.d2-4060553005 .stroke-AB4{stroke:#EDF0FD;}
		.d2-4060553005 .stroke-AB5{stroke:#F7F8FE;}
		.d2-4060553005 .background-color-N1{background-color:#0A0F25;}
		.d2-4060553005 .background-color-N2{background-color:#676C7E;}
		.d2-4060553005 .background-color-N3{background-color:#9499AB;}
		.d2-4060553005 .background-color-N4{background-color:#CFD2DD;}
		.d2-4060553005 .background-color-N5{background-color:#DEE1EB;}
		.d2-4060553005 .background-color-N6{background-color:#EEF1F8;}
		.d2-4060553005 .background-color-N7{background-color:#FFFFFF;}
		.d2-4060553005 .background-color-B1{background-color:#0D32B2;}
		.d2-4060553005 .background-color-B2{background-color:#0D32B2;}
		.d2-4060553005 .background-color-B3{background-color:#E3E9FD;}
		.d2-4060553005 .background-color-B4{background-color:#E3E9FD;}
		.d2-4060553005 .background-color-B5{background-color:#EDF0FD;}
		.d2-4060553005 .background-color-B6{background-color:#F7F8FE;}
		.d2-4060553005 .background-color-AA2{background-color:#4A6FF3;}
		.d2-4060553005 .background-color-AA4{background-color:#EDF0FD;}
		.d2-4060553005 .background-color-AA5{background-color:#F7F8FE;}
		.d2-4060553005 .background-color-AB4{background-color:#EDF0FD;}
		.d2-4060553005 .background-color-AB5{background-color:#F7F8FE;}
		.d2-4060553005 .color-N1{color:#0A0F25;}
		.d2-4060553005 .color-N2{color:#676C7E;}
		.d2-4060553005 .color-N3{color:#9499AB;}
		.d2-4060553005 .color-N4{color:#CFD2DD;}
		.d2-4060553005 .color-N5{color:#DEE1EB;}
		.d2-4060553005 .color-N6{color:#EEF1F8;}
		.d2-4060553005 .color-N7{color:#FFFFFF;}
		.d2-4060553005 .color-B1{color:#0D32B2;}
		.d2-4060553005 .color-B2{color:#0D32B2;}
		.d2-4060553005 .color-B3{color:#E3E9FD;}
		.d2-4060553005 .color-B4{color:#E3E9FD;}
		.d2-4060553005 .color-B5{color:#EDF0FD;}
		.d2-4060553005 .color-B6{color:#F7F8FE;}
		.d2-4060553005 .color-AA2{color:#4A6FF3;}
		.d2-4060553005 .color-AA4{color:#EDF0FD;}
		.d2-4060553005 .color-AA5{color:#F7F8FE;}
		.d2-4060553005 .color-AB4{color:#EDF0FD;}
		.d2-4060553005 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-4060553005);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-4060553005);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-4060553005);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-4060553005);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-4060553005);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-4060553005);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-4060553005);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-4060553005);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-4060553005);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-4060553005);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-4060553005);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-4060553005);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-4060553005);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-4060553005);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-4060553005);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-4060553005);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-4060553005);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-4060553005);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;Q0k=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;10.000000&quot; y=&quot;20.000000&quot; width=&quot;693.000000&quot; height=&quot;356.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#E3E9FD&quot; class=&quot;stroke-B1 fill-B4&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;356.500000&quot; y=&quot;7.000000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:28px&quot;&gt;Clustered Index B-Tree on id&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Q0kuUm9vdA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;298.000000&quot; y=&quot;50.000000&quot; width=&quot;118.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;357.000000&quot; y=&quot;88.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;357.000000&quot; dy=&quot;0.000000&quot;&gt;Root Node&lt;/tspan&gt;&lt;tspan x=&quot;357.000000&quot; dy=&quot;18.500000&quot;&gt;[4 | 7]&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Q0kuTA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;40.000000&quot; y=&quot;232.000000&quot; width=&quot;171.000000&quot; height=&quot;114.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;125.500000&quot; y=&quot;270.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;125.500000&quot; dy=&quot;0.000000&quot;&gt;Leaf Node&lt;/tspan&gt;&lt;tspan x=&quot;125.500000&quot; dy=&quot;17.250000&quot;&gt;[1 → full row data]&lt;/tspan&gt;&lt;tspan x=&quot;125.500000&quot; dy=&quot;17.250000&quot;&gt;[2 → full row data]&lt;/tspan&gt;&lt;tspan x=&quot;125.500000&quot; dy=&quot;17.250000&quot;&gt;[3 → full row data]&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Q0kuTQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;271.000000&quot; y=&quot;232.000000&quot; width=&quot;171.000000&quot; height=&quot;114.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;356.500000&quot; y=&quot;270.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;356.500000&quot; dy=&quot;0.000000&quot;&gt;Leaf Node&lt;/tspan&gt;&lt;tspan x=&quot;356.500000&quot; dy=&quot;17.250000&quot;&gt;[4 → full row data]&lt;/tspan&gt;&lt;tspan x=&quot;356.500000&quot; dy=&quot;17.250000&quot;&gt;[5 → full row data]&lt;/tspan&gt;&lt;tspan x=&quot;356.500000&quot; dy=&quot;17.250000&quot;&gt;[6 → full row data]&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Q0kuUg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;502.000000&quot; y=&quot;232.000000&quot; width=&quot;171.000000&quot; height=&quot;114.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;587.500000&quot; y=&quot;270.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;587.500000&quot; dy=&quot;0.000000&quot;&gt;Leaf Node&lt;/tspan&gt;&lt;tspan x=&quot;587.500000&quot; dy=&quot;17.250000&quot;&gt;[7 → full row data]&lt;/tspan&gt;&lt;tspan x=&quot;587.500000&quot; dy=&quot;17.250000&quot;&gt;[8 → full row data]&lt;/tspan&gt;&lt;tspan x=&quot;587.500000&quot; dy=&quot;17.250000&quot;&gt;[9 → full row data]&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Q0kuKFJvb3QgLSZndDsgTClbMF0=&quot;&gt;&lt;marker id=&quot;mk-d2-4060553005-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 295.639183 114.975045 C 159.899994 168.447998 125.500000 192.000000 125.500000 228.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-4060553005-3488378134)&quot; mask=&quot;url(#d2-4060553005)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;Q0kuKFJvb3QgLSZndDsgTSlbMF0=&quot;&gt;&lt;path d=&quot;M 356.500000 134.000000 C 356.500000 172.000000 356.500000 192.000000 356.500000 228.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-4060553005-3488378134)&quot; mask=&quot;url(#d2-4060553005)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;Q0kuKFJvb3QgLSZndDsgUilbMF0=&quot;&gt;&lt;path d=&quot;M 418.359353 114.978752 C 553.299988 168.447998 587.500000 192.000000 587.500000 228.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-4060553005-3488378134)&quot; mask=&quot;url(#d2-4060553005)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;mask id=&quot;d2-4060553005&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-15&quot; y=&quot;-45&quot; width=&quot;743&quot; height=&quot;446&quot;&gt;
&lt;rect x=&quot;-15&quot; y=&quot;-45&quot; width=&quot;743&quot; height=&quot;446&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;

&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;The leaf level of a clustered index &lt;strong&gt;is&lt;/strong&gt; the table. There is no separate heap. Rows are physically stored in sorted order by the index key.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Range scans are extremely fast — &lt;code&gt;WHERE id BETWEEN 4 AND 7&lt;/code&gt; reads three contiguous leaf pages, no heap fetch.&lt;/li&gt;
&lt;li&gt;No double lookup — one B-tree traversal retrieves the full row.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cost:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Inserts must go into the right sorted position. Random inserts (e.g., UUIDs as keys) cause &lt;strong&gt;page splits&lt;/strong&gt; — when an insert won’t fit in the target page, the database allocates a new page and moves half the rows to it, an expensive operation that fragments the index over time.&lt;/li&gt;
&lt;li&gt;There can only be &lt;strong&gt;one&lt;/strong&gt; clustered index per table — the data can only be physically sorted one way.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Aside — &lt;code&gt;FILLFACTOR&lt;/code&gt;:&lt;/strong&gt; Most databases let you reserve free space on each page at index creation time (PostgreSQL’s &lt;code&gt;WITH (fillfactor = 70)&lt;/code&gt;, MySQL’s similar setting). A 70% fillfactor leaves 30% of each page empty for future inserts and HOT updates, dramatically reducing page splits on write-heavy tables. The tradeoff is read amplification — the index occupies more pages.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&quot;primary-key-vs-clustered-index&quot;&gt;Primary Key vs Clustered Index&lt;/h2&gt;
&lt;p&gt;This is one of the most misunderstood distinctions in databases. They are related but not the same thing.&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 1040 261&quot;&gt;&lt;svg class=&quot;d2-1451731488 d2-svg&quot; width=&quot;1040&quot; height=&quot;261&quot; viewBox=&quot;-25 -2 1040 261&quot;&gt;&lt;rect x=&quot;-25.000000&quot; y=&quot;-2.000000&quot; width=&quot;1040.000000&quot; height=&quot;261.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-1451731488 .text-bold {
	font-family: &quot;d2-1451731488-font-bold&quot;;
}
@font-face {
	font-family: d2-1451731488-font-bold;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-1451731488 .text-italic {
	font-family: &quot;d2-1451731488-font-italic&quot;;
}
@font-face {
	font-family: d2-1451731488-font-italic;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-1451731488 .fill-N1{fill:#0A0F25;}
		.d2-1451731488 .fill-N2{fill:#676C7E;}
		.d2-1451731488 .fill-N3{fill:#9499AB;}
		.d2-1451731488 .fill-N4{fill:#CFD2DD;}
		.d2-1451731488 .fill-N5{fill:#DEE1EB;}
		.d2-1451731488 .fill-N6{fill:#EEF1F8;}
		.d2-1451731488 .fill-N7{fill:#FFFFFF;}
		.d2-1451731488 .fill-B1{fill:#0D32B2;}
		.d2-1451731488 .fill-B2{fill:#0D32B2;}
		.d2-1451731488 .fill-B3{fill:#E3E9FD;}
		.d2-1451731488 .fill-B4{fill:#E3E9FD;}
		.d2-1451731488 .fill-B5{fill:#EDF0FD;}
		.d2-1451731488 .fill-B6{fill:#F7F8FE;}
		.d2-1451731488 .fill-AA2{fill:#4A6FF3;}
		.d2-1451731488 .fill-AA4{fill:#EDF0FD;}
		.d2-1451731488 .fill-AA5{fill:#F7F8FE;}
		.d2-1451731488 .fill-AB4{fill:#EDF0FD;}
		.d2-1451731488 .fill-AB5{fill:#F7F8FE;}
		.d2-1451731488 .stroke-N1{stroke:#0A0F25;}
		.d2-1451731488 .stroke-N2{stroke:#676C7E;}
		.d2-1451731488 .stroke-N3{stroke:#9499AB;}
		.d2-1451731488 .stroke-N4{stroke:#CFD2DD;}
		.d2-1451731488 .stroke-N5{stroke:#DEE1EB;}
		.d2-1451731488 .stroke-N6{stroke:#EEF1F8;}
		.d2-1451731488 .stroke-N7{stroke:#FFFFFF;}
		.d2-1451731488 .stroke-B1{stroke:#0D32B2;}
		.d2-1451731488 .stroke-B2{stroke:#0D32B2;}
		.d2-1451731488 .stroke-B3{stroke:#E3E9FD;}
		.d2-1451731488 .stroke-B4{stroke:#E3E9FD;}
		.d2-1451731488 .stroke-B5{stroke:#EDF0FD;}
		.d2-1451731488 .stroke-B6{stroke:#F7F8FE;}
		.d2-1451731488 .stroke-AA2{stroke:#4A6FF3;}
		.d2-1451731488 .stroke-AA4{stroke:#EDF0FD;}
		.d2-1451731488 .stroke-AA5{stroke:#F7F8FE;}
		.d2-1451731488 .stroke-AB4{stroke:#EDF0FD;}
		.d2-1451731488 .stroke-AB5{stroke:#F7F8FE;}
		.d2-1451731488 .background-color-N1{background-color:#0A0F25;}
		.d2-1451731488 .background-color-N2{background-color:#676C7E;}
		.d2-1451731488 .background-color-N3{background-color:#9499AB;}
		.d2-1451731488 .background-color-N4{background-color:#CFD2DD;}
		.d2-1451731488 .background-color-N5{background-color:#DEE1EB;}
		.d2-1451731488 .background-color-N6{background-color:#EEF1F8;}
		.d2-1451731488 .background-color-N7{background-color:#FFFFFF;}
		.d2-1451731488 .background-color-B1{background-color:#0D32B2;}
		.d2-1451731488 .background-color-B2{background-color:#0D32B2;}
		.d2-1451731488 .background-color-B3{background-color:#E3E9FD;}
		.d2-1451731488 .background-color-B4{background-color:#E3E9FD;}
		.d2-1451731488 .background-color-B5{background-color:#EDF0FD;}
		.d2-1451731488 .background-color-B6{background-color:#F7F8FE;}
		.d2-1451731488 .background-color-AA2{background-color:#4A6FF3;}
		.d2-1451731488 .background-color-AA4{background-color:#EDF0FD;}
		.d2-1451731488 .background-color-AA5{background-color:#F7F8FE;}
		.d2-1451731488 .background-color-AB4{background-color:#EDF0FD;}
		.d2-1451731488 .background-color-AB5{background-color:#F7F8FE;}
		.d2-1451731488 .color-N1{color:#0A0F25;}
		.d2-1451731488 .color-N2{color:#676C7E;}
		.d2-1451731488 .color-N3{color:#9499AB;}
		.d2-1451731488 .color-N4{color:#CFD2DD;}
		.d2-1451731488 .color-N5{color:#DEE1EB;}
		.d2-1451731488 .color-N6{color:#EEF1F8;}
		.d2-1451731488 .color-N7{color:#FFFFFF;}
		.d2-1451731488 .color-B1{color:#0D32B2;}
		.d2-1451731488 .color-B2{color:#0D32B2;}
		.d2-1451731488 .color-B3{color:#E3E9FD;}
		.d2-1451731488 .color-B4{color:#E3E9FD;}
		.d2-1451731488 .color-B5{color:#EDF0FD;}
		.d2-1451731488 .color-B6{color:#F7F8FE;}
		.d2-1451731488 .color-AA2{color:#4A6FF3;}
		.d2-1451731488 .color-AA4{color:#EDF0FD;}
		.d2-1451731488 .color-AA5{color:#F7F8FE;}
		.d2-1451731488 .color-AB4{color:#EDF0FD;}
		.d2-1451731488 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-1451731488);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-1451731488);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-1451731488);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-1451731488);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-1451731488);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-1451731488);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-1451731488);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-1451731488);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-1451731488);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-1451731488);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-1451731488);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-1451731488);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-1451731488);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-1451731488);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-1451731488);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-1451731488);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-1451731488);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-1451731488);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;UEs=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;0.000000&quot; y=&quot;49.000000&quot; width=&quot;209.000000&quot; height=&quot;130.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;104.500000&quot; y=&quot;87.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;104.500000&quot; dy=&quot;0.000000&quot;&gt;Primary Key&lt;/tspan&gt;&lt;tspan x=&quot;104.500000&quot; dy=&quot;17.000000&quot;&gt;A logical constraint:&lt;/tspan&gt;&lt;tspan x=&quot;104.500000&quot; dy=&quot;17.000000&quot;&gt;• Uniqueness enforced&lt;/tspan&gt;&lt;tspan x=&quot;104.500000&quot; dy=&quot;17.000000&quot;&gt;• NOT NULL enforced&lt;/tspan&gt;&lt;tspan x=&quot;104.500000&quot; dy=&quot;17.000000&quot;&gt;• One per table&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Q0k=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;733.000000&quot; y=&quot;49.000000&quot; width=&quot;257.000000&quot; height=&quot;130.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;861.500000&quot; y=&quot;87.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;861.500000&quot; dy=&quot;0.000000&quot;&gt;Clustered Index&lt;/tspan&gt;&lt;tspan x=&quot;861.500000&quot; dy=&quot;17.000000&quot;&gt;A physical storage decision:&lt;/tspan&gt;&lt;tspan x=&quot;861.500000&quot; dy=&quot;17.000000&quot;&gt;• Data sorted by this key&lt;/tspan&gt;&lt;tspan x=&quot;861.500000&quot; dy=&quot;17.000000&quot;&gt;• Leaf nodes hold actual rows&lt;/tspan&gt;&lt;tspan x=&quot;861.500000&quot; dy=&quot;17.000000&quot;&gt;• One per table&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFBLIC0mZ3Q7IENJKVswXQ==&quot;&gt;&lt;marker id=&quot;mk-d2-1451731488-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 210.947900 89.046472 C 418.600006 40.699001 523.400024 39.900002 729.091429 84.649662&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1451731488-3488378134)&quot; mask=&quot;url(#d2-1451731488)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;470.500000&quot; y=&quot;38.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;470.500000&quot; dy=&quot;0.000000&quot;&gt;InnoDB (MySQL):&lt;/tspan&gt;&lt;tspan x=&quot;470.500000&quot; dy=&quot;18.500000&quot;&gt;PK always IS the clustered index&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFBLIC0mZ3Q7IENJKVsxXQ==&quot;&gt;&lt;path d=&quot;M 211.000000 113.500000 C 418.600006 113.500000 523.400024 113.500000 729.000000 113.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1451731488-3488378134)&quot; mask=&quot;url(#d2-1451731488)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;471.000000&quot; y=&quot;103.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;471.000000&quot; dy=&quot;0.000000&quot;&gt;SQL Server:&lt;/tspan&gt;&lt;tspan x=&quot;471.000000&quot; dy=&quot;17.666667&quot;&gt;PK creates clustered index by default&lt;/tspan&gt;&lt;tspan x=&quot;471.000000&quot; dy=&quot;17.666667&quot;&gt;(can be overridden)&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFBLIC0mZ3Q7IENJKVsyXQ==&quot;&gt;&lt;marker id=&quot;mk-d2-1451731488-2177206569&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B2&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 210.928505 143.029971 C 418.600006 200.100006 523.400024 200.899994 729.128278 147.504874&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:6.000000,5.919384;&quot; marker-end=&quot;url(#mk-d2-1451731488-2177206569)&quot; mask=&quot;url(#d2-1451731488)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;471.000000&quot; y=&quot;182.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;471.000000&quot; dy=&quot;0.000000&quot;&gt;PostgreSQL:&lt;/tspan&gt;&lt;tspan x=&quot;471.000000&quot; dy=&quot;17.250000&quot;&gt;No clustered indexes.&lt;/tspan&gt;&lt;tspan x=&quot;471.000000&quot; dy=&quot;17.250000&quot;&gt;PK creates a B-tree index&lt;/tspan&gt;&lt;tspan x=&quot;471.000000&quot; dy=&quot;17.250000&quot;&gt;on a heap. Always.&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;mask id=&quot;d2-1451731488&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-25&quot; y=&quot;-2&quot; width=&quot;1040&quot; height=&quot;261&quot;&gt;
&lt;rect x=&quot;-25&quot; y=&quot;-2&quot; width=&quot;1040&quot; height=&quot;261&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;363.000000&quot; y=&quot;22.000000&quot; width=&quot;215&quot; height=&quot;37&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;348.000000&quot; y=&quot;87.000000&quot; width=&quot;246&quot; height=&quot;53&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;387.000000&quot; y=&quot;166.000000&quot; width=&quot;168&quot; height=&quot;69&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;h3 id=&quot;mysql-innodb&quot;&gt;MySQL InnoDB&lt;/h3&gt;
&lt;p&gt;InnoDB &lt;strong&gt;always&lt;/strong&gt; has a clustered index. If you define a primary key, it becomes the clustered index. If you don’t, InnoDB finds the first unique NOT NULL column. If none exists, InnoDB creates a hidden 6-byte row ID and clusters on that. You cannot opt out.&lt;/p&gt;
&lt;h3 id=&quot;sql-server&quot;&gt;SQL Server&lt;/h3&gt;
&lt;p&gt;A primary key creates a clustered index by default — but you can override this. You can create a primary key as a non-clustered index, and separately define a different column as the clustered index. Primary key and clustered index are independent choices.&lt;/p&gt;
&lt;h3 id=&quot;postgresql&quot;&gt;PostgreSQL&lt;/h3&gt;
&lt;p&gt;PostgreSQL &lt;strong&gt;has no clustered indexes&lt;/strong&gt; in the traditional sense. All tables are heaps. A primary key creates a regular B-tree index that stores row IDs pointing back to the heap. The &lt;code&gt;CLUSTER&lt;/code&gt; command can physically reorder a table’s pages to match an index — but this ordering is not maintained on subsequent writes. It’s a one-time reorganization, not a structural property.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;secondary-indexes&quot;&gt;Secondary Indexes&lt;/h2&gt;
&lt;p&gt;A secondary index is any index that is not the clustered index. How it works depends on the table’s storage structure.&lt;/p&gt;
&lt;h3 id=&quot;secondary-index-on-a-heap-table-postgresql&quot;&gt;Secondary Index on a Heap Table (PostgreSQL)&lt;/h3&gt;
&lt;p&gt;Both the primary key index and any secondary indexes are B-trees pointing to physical row IDs (ctid).&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 907 535&quot;&gt;&lt;svg class=&quot;d2-1533636968 d2-svg&quot; width=&quot;907&quot; height=&quot;535&quot; viewBox=&quot;-15 -45 907 535&quot;&gt;&lt;rect x=&quot;-15.000000&quot; y=&quot;-45.000000&quot; width=&quot;907.000000&quot; height=&quot;535.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-1533636968 .text {
	font-family: &quot;d2-1533636968-font-regular&quot;;
}
@font-face {
	font-family: d2-1533636968-font-regular;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-1533636968 .text-bold {
	font-family: &quot;d2-1533636968-font-bold&quot;;
}
@font-face {
	font-family: d2-1533636968-font-bold;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-1533636968 .text-italic {
	font-family: &quot;d2-1533636968-font-italic&quot;;
}
@font-face {
	font-family: d2-1533636968-font-italic;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-1533636968 .fill-N1{fill:#0A0F25;}
		.d2-1533636968 .fill-N2{fill:#676C7E;}
		.d2-1533636968 .fill-N3{fill:#9499AB;}
		.d2-1533636968 .fill-N4{fill:#CFD2DD;}
		.d2-1533636968 .fill-N5{fill:#DEE1EB;}
		.d2-1533636968 .fill-N6{fill:#EEF1F8;}
		.d2-1533636968 .fill-N7{fill:#FFFFFF;}
		.d2-1533636968 .fill-B1{fill:#0D32B2;}
		.d2-1533636968 .fill-B2{fill:#0D32B2;}
		.d2-1533636968 .fill-B3{fill:#E3E9FD;}
		.d2-1533636968 .fill-B4{fill:#E3E9FD;}
		.d2-1533636968 .fill-B5{fill:#EDF0FD;}
		.d2-1533636968 .fill-B6{fill:#F7F8FE;}
		.d2-1533636968 .fill-AA2{fill:#4A6FF3;}
		.d2-1533636968 .fill-AA4{fill:#EDF0FD;}
		.d2-1533636968 .fill-AA5{fill:#F7F8FE;}
		.d2-1533636968 .fill-AB4{fill:#EDF0FD;}
		.d2-1533636968 .fill-AB5{fill:#F7F8FE;}
		.d2-1533636968 .stroke-N1{stroke:#0A0F25;}
		.d2-1533636968 .stroke-N2{stroke:#676C7E;}
		.d2-1533636968 .stroke-N3{stroke:#9499AB;}
		.d2-1533636968 .stroke-N4{stroke:#CFD2DD;}
		.d2-1533636968 .stroke-N5{stroke:#DEE1EB;}
		.d2-1533636968 .stroke-N6{stroke:#EEF1F8;}
		.d2-1533636968 .stroke-N7{stroke:#FFFFFF;}
		.d2-1533636968 .stroke-B1{stroke:#0D32B2;}
		.d2-1533636968 .stroke-B2{stroke:#0D32B2;}
		.d2-1533636968 .stroke-B3{stroke:#E3E9FD;}
		.d2-1533636968 .stroke-B4{stroke:#E3E9FD;}
		.d2-1533636968 .stroke-B5{stroke:#EDF0FD;}
		.d2-1533636968 .stroke-B6{stroke:#F7F8FE;}
		.d2-1533636968 .stroke-AA2{stroke:#4A6FF3;}
		.d2-1533636968 .stroke-AA4{stroke:#EDF0FD;}
		.d2-1533636968 .stroke-AA5{stroke:#F7F8FE;}
		.d2-1533636968 .stroke-AB4{stroke:#EDF0FD;}
		.d2-1533636968 .stroke-AB5{stroke:#F7F8FE;}
		.d2-1533636968 .background-color-N1{background-color:#0A0F25;}
		.d2-1533636968 .background-color-N2{background-color:#676C7E;}
		.d2-1533636968 .background-color-N3{background-color:#9499AB;}
		.d2-1533636968 .background-color-N4{background-color:#CFD2DD;}
		.d2-1533636968 .background-color-N5{background-color:#DEE1EB;}
		.d2-1533636968 .background-color-N6{background-color:#EEF1F8;}
		.d2-1533636968 .background-color-N7{background-color:#FFFFFF;}
		.d2-1533636968 .background-color-B1{background-color:#0D32B2;}
		.d2-1533636968 .background-color-B2{background-color:#0D32B2;}
		.d2-1533636968 .background-color-B3{background-color:#E3E9FD;}
		.d2-1533636968 .background-color-B4{background-color:#E3E9FD;}
		.d2-1533636968 .background-color-B5{background-color:#EDF0FD;}
		.d2-1533636968 .background-color-B6{background-color:#F7F8FE;}
		.d2-1533636968 .background-color-AA2{background-color:#4A6FF3;}
		.d2-1533636968 .background-color-AA4{background-color:#EDF0FD;}
		.d2-1533636968 .background-color-AA5{background-color:#F7F8FE;}
		.d2-1533636968 .background-color-AB4{background-color:#EDF0FD;}
		.d2-1533636968 .background-color-AB5{background-color:#F7F8FE;}
		.d2-1533636968 .color-N1{color:#0A0F25;}
		.d2-1533636968 .color-N2{color:#676C7E;}
		.d2-1533636968 .color-N3{color:#9499AB;}
		.d2-1533636968 .color-N4{color:#CFD2DD;}
		.d2-1533636968 .color-N5{color:#DEE1EB;}
		.d2-1533636968 .color-N6{color:#EEF1F8;}
		.d2-1533636968 .color-N7{color:#FFFFFF;}
		.d2-1533636968 .color-B1{color:#0D32B2;}
		.d2-1533636968 .color-B2{color:#0D32B2;}
		.d2-1533636968 .color-B3{color:#E3E9FD;}
		.d2-1533636968 .color-B4{color:#E3E9FD;}
		.d2-1533636968 .color-B5{color:#EDF0FD;}
		.d2-1533636968 .color-B6{color:#F7F8FE;}
		.d2-1533636968 .color-AA2{color:#4A6FF3;}
		.d2-1533636968 .color-AA4{color:#EDF0FD;}
		.d2-1533636968 .color-AA5{color:#F7F8FE;}
		.d2-1533636968 .color-AB4{color:#EDF0FD;}
		.d2-1533636968 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-1533636968);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-1533636968);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-1533636968);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-1533636968);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-1533636968);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-1533636968);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-1533636968);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-1533636968);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-1533636968);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-1533636968);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-1533636968);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-1533636968);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-1533636968);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-1533636968);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-1533636968);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-1533636968);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-1533636968);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-1533636968);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;U0k=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;311.000000&quot; y=&quot;20.000000&quot; width=&quot;248.000000&quot; height=&quot;158.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#E3E9FD&quot; class=&quot;stroke-B1 fill-B4&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;435.000000&quot; y=&quot;7.000000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:28px&quot;&gt;Secondary Index on email&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;SGVhcA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;10.000000&quot; y=&quot;339.000000&quot; width=&quot;857.000000&quot; height=&quot;126.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#E3E9FD&quot; class=&quot;stroke-B1 fill-B4&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;438.500000&quot; y=&quot;326.000000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:28px&quot;&gt;Heap&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;U0kuTGVhZg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;341.000000&quot; y=&quot;50.000000&quot; width=&quot;188.000000&quot; height=&quot;98.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;435.000000&quot; y=&quot;88.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;435.000000&quot; dy=&quot;0.000000&quot;&gt;alice@x.com → (2,1)&lt;/tspan&gt;&lt;tspan x=&quot;435.000000&quot; dy=&quot;17.666667&quot;&gt;bob@x.com → (1,3)&lt;/tspan&gt;&lt;tspan x=&quot;435.000000&quot; dy=&quot;17.666667&quot;&gt;carol@x.com → (3,2)&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;SGVhcC5QMQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;40.000000&quot; y=&quot;369.000000&quot; width=&quot;221.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;150.500000&quot; y=&quot;407.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Page 1 · Slot 3: bob&apos;s row&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;SGVhcC5QMg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;321.000000&quot; y=&quot;369.000000&quot; width=&quot;227.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;434.500000&quot; y=&quot;407.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Page 2 · Slot 1: alice&apos;s row&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;SGVhcC5QMw==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;608.000000&quot; y=&quot;369.000000&quot; width=&quot;229.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;722.500000&quot; y=&quot;407.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Page 3 · Slot 2: carol&apos;s row&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFNJLkxlYWYgLSZndDsgSGVhcC5QMilbMF0=&quot;&gt;&lt;marker id=&quot;mk-d2-1533636968-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 434.500000 150.000000 C 434.500000 188.000000 434.500000 210.100006 434.500000 228.250000 C 434.500000 246.399994 434.500000 329.000000 434.500000 365.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1533636968-3488378134)&quot; mask=&quot;url(#d2-1533636968)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;434.500000&quot; y=&quot;264.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;(2,1)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFNJLkxlYWYgLSZndDsgSGVhcC5QMSlbMF0=&quot;&gt;&lt;path d=&quot;M 338.611456 132.425330 C 188.500000 184.753006 150.500000 210.100006 150.500000 228.250000 C 150.500000 246.399994 150.500000 329.000000 150.500000 365.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1533636968-3488378134)&quot; mask=&quot;url(#d2-1533636968)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;170.500000&quot; y=&quot;202.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;(1,3)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFNJLkxlYWYgLSZndDsgSGVhcC5QMylbMF0=&quot;&gt;&lt;path d=&quot;M 531.390336 131.965166 C 683.900024 184.662003 722.500000 210.100006 722.500000 228.250000 C 722.500000 246.399994 722.500000 329.000000 722.500000 365.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1533636968-3488378134)&quot; mask=&quot;url(#d2-1533636968)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;701.500000&quot; y=&quot;202.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;(3,2)&lt;/text&gt;&lt;/g&gt;&lt;mask id=&quot;d2-1533636968&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-15&quot; y=&quot;-45&quot; width=&quot;907&quot; height=&quot;535&quot;&gt;
&lt;rect x=&quot;-15&quot; y=&quot;-45&quot; width=&quot;907&quot; height=&quot;535&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;419.000000&quot; y=&quot;248.000000&quot; width=&quot;31&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;155.000000&quot; y=&quot;186.000000&quot; width=&quot;31&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;686.000000&quot; y=&quot;186.000000&quot; width=&quot;31&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Problem with heap + secondary index:&lt;/strong&gt; If a row is vacuumed and moves to a different page, every index pointing to that row ID must be updated. PostgreSQL’s &lt;strong&gt;HOT (Heap-Only Tuple)&lt;/strong&gt; optimization handles a different case: when an &lt;code&gt;UPDATE&lt;/code&gt; doesn’t change any indexed column, Postgres places the new row version on the same page and chains it from the old one — so no new index entries need to be created. This avoids index bloat from frequent updates to non-indexed columns and keeps secondary indexes pointing at the page rather than at every individual row version.&lt;/p&gt;
&lt;h3 id=&quot;secondary-index-on-a-clustered-table-mysql-innodb&quot;&gt;Secondary Index on a Clustered Table (MySQL InnoDB)&lt;/h3&gt;
&lt;p&gt;Secondary indexes don’t store physical row IDs — they store the &lt;strong&gt;primary key value&lt;/strong&gt; instead. To fetch the full row, InnoDB does a secondary index lookup followed by a primary key (clustered index) lookup.&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 393 567&quot;&gt;&lt;svg class=&quot;d2-1424738927 d2-svg&quot; width=&quot;393&quot; height=&quot;567&quot; viewBox=&quot;-32 -45 393 567&quot;&gt;&lt;rect x=&quot;-32.000000&quot; y=&quot;-45.000000&quot; width=&quot;393.000000&quot; height=&quot;567.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-1424738927 .text {
	font-family: &quot;d2-1424738927-font-regular&quot;;
}
@font-face {
	font-family: d2-1424738927-font-regular;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-1424738927 .text-bold {
	font-family: &quot;d2-1424738927-font-bold&quot;;
}
@font-face {
	font-family: d2-1424738927-font-bold;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-1424738927 .text-italic {
	font-family: &quot;d2-1424738927-font-italic&quot;;
}
@font-face {
	font-family: d2-1424738927-font-italic;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-1424738927 .fill-N1{fill:#0A0F25;}
		.d2-1424738927 .fill-N2{fill:#676C7E;}
		.d2-1424738927 .fill-N3{fill:#9499AB;}
		.d2-1424738927 .fill-N4{fill:#CFD2DD;}
		.d2-1424738927 .fill-N5{fill:#DEE1EB;}
		.d2-1424738927 .fill-N6{fill:#EEF1F8;}
		.d2-1424738927 .fill-N7{fill:#FFFFFF;}
		.d2-1424738927 .fill-B1{fill:#0D32B2;}
		.d2-1424738927 .fill-B2{fill:#0D32B2;}
		.d2-1424738927 .fill-B3{fill:#E3E9FD;}
		.d2-1424738927 .fill-B4{fill:#E3E9FD;}
		.d2-1424738927 .fill-B5{fill:#EDF0FD;}
		.d2-1424738927 .fill-B6{fill:#F7F8FE;}
		.d2-1424738927 .fill-AA2{fill:#4A6FF3;}
		.d2-1424738927 .fill-AA4{fill:#EDF0FD;}
		.d2-1424738927 .fill-AA5{fill:#F7F8FE;}
		.d2-1424738927 .fill-AB4{fill:#EDF0FD;}
		.d2-1424738927 .fill-AB5{fill:#F7F8FE;}
		.d2-1424738927 .stroke-N1{stroke:#0A0F25;}
		.d2-1424738927 .stroke-N2{stroke:#676C7E;}
		.d2-1424738927 .stroke-N3{stroke:#9499AB;}
		.d2-1424738927 .stroke-N4{stroke:#CFD2DD;}
		.d2-1424738927 .stroke-N5{stroke:#DEE1EB;}
		.d2-1424738927 .stroke-N6{stroke:#EEF1F8;}
		.d2-1424738927 .stroke-N7{stroke:#FFFFFF;}
		.d2-1424738927 .stroke-B1{stroke:#0D32B2;}
		.d2-1424738927 .stroke-B2{stroke:#0D32B2;}
		.d2-1424738927 .stroke-B3{stroke:#E3E9FD;}
		.d2-1424738927 .stroke-B4{stroke:#E3E9FD;}
		.d2-1424738927 .stroke-B5{stroke:#EDF0FD;}
		.d2-1424738927 .stroke-B6{stroke:#F7F8FE;}
		.d2-1424738927 .stroke-AA2{stroke:#4A6FF3;}
		.d2-1424738927 .stroke-AA4{stroke:#EDF0FD;}
		.d2-1424738927 .stroke-AA5{stroke:#F7F8FE;}
		.d2-1424738927 .stroke-AB4{stroke:#EDF0FD;}
		.d2-1424738927 .stroke-AB5{stroke:#F7F8FE;}
		.d2-1424738927 .background-color-N1{background-color:#0A0F25;}
		.d2-1424738927 .background-color-N2{background-color:#676C7E;}
		.d2-1424738927 .background-color-N3{background-color:#9499AB;}
		.d2-1424738927 .background-color-N4{background-color:#CFD2DD;}
		.d2-1424738927 .background-color-N5{background-color:#DEE1EB;}
		.d2-1424738927 .background-color-N6{background-color:#EEF1F8;}
		.d2-1424738927 .background-color-N7{background-color:#FFFFFF;}
		.d2-1424738927 .background-color-B1{background-color:#0D32B2;}
		.d2-1424738927 .background-color-B2{background-color:#0D32B2;}
		.d2-1424738927 .background-color-B3{background-color:#E3E9FD;}
		.d2-1424738927 .background-color-B4{background-color:#E3E9FD;}
		.d2-1424738927 .background-color-B5{background-color:#EDF0FD;}
		.d2-1424738927 .background-color-B6{background-color:#F7F8FE;}
		.d2-1424738927 .background-color-AA2{background-color:#4A6FF3;}
		.d2-1424738927 .background-color-AA4{background-color:#EDF0FD;}
		.d2-1424738927 .background-color-AA5{background-color:#F7F8FE;}
		.d2-1424738927 .background-color-AB4{background-color:#EDF0FD;}
		.d2-1424738927 .background-color-AB5{background-color:#F7F8FE;}
		.d2-1424738927 .color-N1{color:#0A0F25;}
		.d2-1424738927 .color-N2{color:#676C7E;}
		.d2-1424738927 .color-N3{color:#9499AB;}
		.d2-1424738927 .color-N4{color:#CFD2DD;}
		.d2-1424738927 .color-N5{color:#DEE1EB;}
		.d2-1424738927 .color-N6{color:#EEF1F8;}
		.d2-1424738927 .color-N7{color:#FFFFFF;}
		.d2-1424738927 .color-B1{color:#0D32B2;}
		.d2-1424738927 .color-B2{color:#0D32B2;}
		.d2-1424738927 .color-B3{color:#E3E9FD;}
		.d2-1424738927 .color-B4{color:#E3E9FD;}
		.d2-1424738927 .color-B5{color:#EDF0FD;}
		.d2-1424738927 .color-B6{color:#F7F8FE;}
		.d2-1424738927 .color-AA2{color:#4A6FF3;}
		.d2-1424738927 .color-AA4{color:#EDF0FD;}
		.d2-1424738927 .color-AA5{color:#F7F8FE;}
		.d2-1424738927 .color-AB4{color:#EDF0FD;}
		.d2-1424738927 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-1424738927);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-1424738927);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-1424738927);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-1424738927);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-1424738927);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-1424738927);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-1424738927);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-1424738927);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-1424738927);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-1424738927);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-1424738927);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-1424738927);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-1424738927);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-1424738927);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-1424738927);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-1424738927);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-1424738927);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-1424738927);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;U0k=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;48.000000&quot; y=&quot;20.000000&quot; width=&quot;252.000000&quot; height=&quot;158.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#E3E9FD&quot; class=&quot;stroke-B1 fill-B4&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;174.000000&quot; y=&quot;7.000000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:28px&quot;&gt;Secondary Index on email&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Q0k=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;33.000000&quot; y=&quot;339.000000&quot; width=&quot;262.000000&quot; height=&quot;158.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#E3E9FD&quot; class=&quot;stroke-B1 fill-B4&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;164.000000&quot; y=&quot;326.000000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:28px&quot;&gt;Clustered Index (Primary Key)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;U0kuTGVhZg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;78.000000&quot; y=&quot;50.000000&quot; width=&quot;192.000000&quot; height=&quot;98.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;174.000000&quot; y=&quot;88.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;174.000000&quot; dy=&quot;0.000000&quot;&gt;alice@x.com → PK=3&lt;/tspan&gt;&lt;tspan x=&quot;174.000000&quot; dy=&quot;17.666667&quot;&gt;bob@x.com → PK=1&lt;/tspan&gt;&lt;tspan x=&quot;174.000000&quot; dy=&quot;17.666667&quot;&gt;carol@x.com → PK=7&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Q0kuTGVhZg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;63.000000&quot; y=&quot;369.000000&quot; width=&quot;202.000000&quot; height=&quot;98.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;164.000000&quot; y=&quot;407.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;164.000000&quot; dy=&quot;0.000000&quot;&gt;PK=1 → full row (bob)&lt;/tspan&gt;&lt;tspan x=&quot;164.000000&quot; dy=&quot;17.666667&quot;&gt;PK=3 → full row (alice)&lt;/tspan&gt;&lt;tspan x=&quot;164.000000&quot; dy=&quot;17.666667&quot;&gt;PK=7 → full row (carol)&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFNJLkxlYWYgLSZndDsgQ0kuTGVhZilbMF0=&quot;&gt;&lt;marker id=&quot;mk-d2-1424738927-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 136.310314 149.607684 C 107.900002 188.000000 100.500000 210.100006 100.500000 228.250000 C 100.500000 246.399994 106.900002 329.000000 130.343785 365.630914&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1424738927-3488378134)&quot; mask=&quot;url(#d2-1424738927)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;101.000000&quot; y=&quot;262.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;PK=3&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFNJLkxlYWYgLSZndDsgQ0kuTGVhZilbMV0=&quot;&gt;&lt;path d=&quot;M 174.000000 150.000000 C 174.000000 188.000000 174.000000 210.100006 174.000000 228.250000 C 174.000000 246.399994 173.000000 329.000000 169.398015 365.019851&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1424738927-3488378134)&quot; mask=&quot;url(#d2-1424738927)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;173.500000&quot; y=&quot;264.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;PK=1&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFNJLkxlYWYgLSZndDsgQ0kuTGVhZilbMl0=&quot;&gt;&lt;path d=&quot;M 212.189686 149.607684 C 240.600006 188.000000 248.000000 210.100006 248.000000 228.250000 C 248.000000 246.399994 239.600006 329.000000 208.572769 365.937181&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1424738927-3488378134)&quot; mask=&quot;url(#d2-1424738927)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;246.500000&quot; y=&quot;265.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;PK=7&lt;/text&gt;&lt;/g&gt;&lt;mask id=&quot;d2-1424738927&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-32&quot; y=&quot;-45&quot; width=&quot;393&quot; height=&quot;567&quot;&gt;
&lt;rect x=&quot;-32&quot; y=&quot;-45&quot; width=&quot;393&quot; height=&quot;567&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;82.000000&quot; y=&quot;246.000000&quot; width=&quot;38&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;155.000000&quot; y=&quot;248.000000&quot; width=&quot;37&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;227.000000&quot; y=&quot;249.000000&quot; width=&quot;39&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Why primary key value instead of physical address?&lt;/strong&gt;
When a clustered index page splits (due to an insert), rows shift around. If secondary indexes stored physical addresses, every secondary index would need updating on every page split. By storing the primary key, secondary indexes remain stable — only the clustered index itself needs to maintain the physical layout.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cost:&lt;/strong&gt; Every secondary index lookup on InnoDB requires two B-tree traversals — one in the secondary index, one in the clustered index. This is called a &lt;strong&gt;double lookup&lt;/strong&gt; (also called a &lt;em&gt;bookmark lookup&lt;/em&gt; in SQL Server terminology).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mitigation — Covering Index:&lt;/strong&gt; If the query only needs columns that are already in the index, the database doesn’t need to look up the full row at all. A covering index includes all columns needed by the query, allowing the lookup to be resolved entirely from the index leaf node.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- Without covering index: secondary index lookup + clustered index lookup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; email, created_at &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; users &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; email &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;alice@x.com&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- With covering index on (email, created_at): resolved from index alone&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; idx_email_created&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; users (email, created_at);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;how-it-all-connects&quot;&gt;How It All Connects&lt;/h2&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 587 1240&quot;&gt;&lt;svg class=&quot;d2-1991294913 d2-svg&quot; width=&quot;587&quot; height=&quot;1240&quot; viewBox=&quot;-25 -25 587 1240&quot;&gt;&lt;rect x=&quot;-25.000000&quot; y=&quot;-25.000000&quot; width=&quot;587.000000&quot; height=&quot;1240.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-1991294913 .text-bold {
	font-family: &quot;d2-1991294913-font-bold&quot;;
}
@font-face {
	font-family: d2-1991294913-font-bold;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-1991294913 .fill-N1{fill:#0A0F25;}
		.d2-1991294913 .fill-N2{fill:#676C7E;}
		.d2-1991294913 .fill-N3{fill:#9499AB;}
		.d2-1991294913 .fill-N4{fill:#CFD2DD;}
		.d2-1991294913 .fill-N5{fill:#DEE1EB;}
		.d2-1991294913 .fill-N6{fill:#EEF1F8;}
		.d2-1991294913 .fill-N7{fill:#FFFFFF;}
		.d2-1991294913 .fill-B1{fill:#0D32B2;}
		.d2-1991294913 .fill-B2{fill:#0D32B2;}
		.d2-1991294913 .fill-B3{fill:#E3E9FD;}
		.d2-1991294913 .fill-B4{fill:#E3E9FD;}
		.d2-1991294913 .fill-B5{fill:#EDF0FD;}
		.d2-1991294913 .fill-B6{fill:#F7F8FE;}
		.d2-1991294913 .fill-AA2{fill:#4A6FF3;}
		.d2-1991294913 .fill-AA4{fill:#EDF0FD;}
		.d2-1991294913 .fill-AA5{fill:#F7F8FE;}
		.d2-1991294913 .fill-AB4{fill:#EDF0FD;}
		.d2-1991294913 .fill-AB5{fill:#F7F8FE;}
		.d2-1991294913 .stroke-N1{stroke:#0A0F25;}
		.d2-1991294913 .stroke-N2{stroke:#676C7E;}
		.d2-1991294913 .stroke-N3{stroke:#9499AB;}
		.d2-1991294913 .stroke-N4{stroke:#CFD2DD;}
		.d2-1991294913 .stroke-N5{stroke:#DEE1EB;}
		.d2-1991294913 .stroke-N6{stroke:#EEF1F8;}
		.d2-1991294913 .stroke-N7{stroke:#FFFFFF;}
		.d2-1991294913 .stroke-B1{stroke:#0D32B2;}
		.d2-1991294913 .stroke-B2{stroke:#0D32B2;}
		.d2-1991294913 .stroke-B3{stroke:#E3E9FD;}
		.d2-1991294913 .stroke-B4{stroke:#E3E9FD;}
		.d2-1991294913 .stroke-B5{stroke:#EDF0FD;}
		.d2-1991294913 .stroke-B6{stroke:#F7F8FE;}
		.d2-1991294913 .stroke-AA2{stroke:#4A6FF3;}
		.d2-1991294913 .stroke-AA4{stroke:#EDF0FD;}
		.d2-1991294913 .stroke-AA5{stroke:#F7F8FE;}
		.d2-1991294913 .stroke-AB4{stroke:#EDF0FD;}
		.d2-1991294913 .stroke-AB5{stroke:#F7F8FE;}
		.d2-1991294913 .background-color-N1{background-color:#0A0F25;}
		.d2-1991294913 .background-color-N2{background-color:#676C7E;}
		.d2-1991294913 .background-color-N3{background-color:#9499AB;}
		.d2-1991294913 .background-color-N4{background-color:#CFD2DD;}
		.d2-1991294913 .background-color-N5{background-color:#DEE1EB;}
		.d2-1991294913 .background-color-N6{background-color:#EEF1F8;}
		.d2-1991294913 .background-color-N7{background-color:#FFFFFF;}
		.d2-1991294913 .background-color-B1{background-color:#0D32B2;}
		.d2-1991294913 .background-color-B2{background-color:#0D32B2;}
		.d2-1991294913 .background-color-B3{background-color:#E3E9FD;}
		.d2-1991294913 .background-color-B4{background-color:#E3E9FD;}
		.d2-1991294913 .background-color-B5{background-color:#EDF0FD;}
		.d2-1991294913 .background-color-B6{background-color:#F7F8FE;}
		.d2-1991294913 .background-color-AA2{background-color:#4A6FF3;}
		.d2-1991294913 .background-color-AA4{background-color:#EDF0FD;}
		.d2-1991294913 .background-color-AA5{background-color:#F7F8FE;}
		.d2-1991294913 .background-color-AB4{background-color:#EDF0FD;}
		.d2-1991294913 .background-color-AB5{background-color:#F7F8FE;}
		.d2-1991294913 .color-N1{color:#0A0F25;}
		.d2-1991294913 .color-N2{color:#676C7E;}
		.d2-1991294913 .color-N3{color:#9499AB;}
		.d2-1991294913 .color-N4{color:#CFD2DD;}
		.d2-1991294913 .color-N5{color:#DEE1EB;}
		.d2-1991294913 .color-N6{color:#EEF1F8;}
		.d2-1991294913 .color-N7{color:#FFFFFF;}
		.d2-1991294913 .color-B1{color:#0D32B2;}
		.d2-1991294913 .color-B2{color:#0D32B2;}
		.d2-1991294913 .color-B3{color:#E3E9FD;}
		.d2-1991294913 .color-B4{color:#E3E9FD;}
		.d2-1991294913 .color-B5{color:#EDF0FD;}
		.d2-1991294913 .color-B6{color:#F7F8FE;}
		.d2-1991294913 .color-AA2{color:#4A6FF3;}
		.d2-1991294913 .color-AA4{color:#EDF0FD;}
		.d2-1991294913 .color-AA5{color:#F7F8FE;}
		.d2-1991294913 .color-AB4{color:#EDF0FD;}
		.d2-1991294913 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-1991294913);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-1991294913);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-1991294913);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-1991294913);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-1991294913);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-1991294913);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-1991294913);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-1991294913);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-1991294913);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-1991294913);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-1991294913);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-1991294913);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-1991294913);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-1991294913);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-1991294913);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-1991294913);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-1991294913);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-1991294913);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;VA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;164.000000&quot; y=&quot;0.000000&quot; width=&quot;214.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;271.000000&quot; y=&quot;38.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;271.000000&quot; dy=&quot;0.000000&quot;&gt;Table&lt;/tspan&gt;&lt;tspan x=&quot;271.000000&quot; dy=&quot;18.500000&quot;&gt;Logical: columns + rows&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;SA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;155.000000&quot; y=&quot;182.000000&quot; width=&quot;231.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;270.500000&quot; y=&quot;220.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;270.500000&quot; dy=&quot;0.000000&quot;&gt;Heap&lt;/tspan&gt;&lt;tspan x=&quot;270.500000&quot; dy=&quot;18.500000&quot;&gt;Physical: unordered pages&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;UA==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;169.000000&quot; y=&quot;364.000000&quot; width=&quot;204.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;271.000000&quot; y=&quot;402.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;271.000000&quot; dy=&quot;0.000000&quot;&gt;Page&lt;/tspan&gt;&lt;tspan x=&quot;271.000000&quot; dy=&quot;18.500000&quot;&gt;8KB block — unit of I/O&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Ug==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;162.000000&quot; y=&quot;546.000000&quot; width=&quot;218.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;271.000000&quot; y=&quot;584.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;271.000000&quot; dy=&quot;0.000000&quot;&gt;Row&lt;/tspan&gt;&lt;tspan x=&quot;271.000000&quot; dy=&quot;18.500000&quot;&gt;Stored inside a page slot&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;UklE&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;146.000000&quot; y=&quot;728.000000&quot; width=&quot;250.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;271.000000&quot; y=&quot;766.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;271.000000&quot; dy=&quot;0.000000&quot;&gt;Row ID / ctid / ROWID&lt;/tspan&gt;&lt;tspan x=&quot;271.000000&quot; dy=&quot;18.500000&quot;&gt;Physical address: (page, slot)&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;SVg=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;145.000000&quot; y=&quot;910.000000&quot; width=&quot;252.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;271.000000&quot; y=&quot;948.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;271.000000&quot; dy=&quot;0.000000&quot;&gt;B-Tree Index&lt;/tspan&gt;&lt;tspan x=&quot;271.000000&quot; dy=&quot;18.500000&quot;&gt;Maps values → Row IDs or PKs&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Q0k=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;0.000000&quot; y=&quot;1092.000000&quot; width=&quot;243.000000&quot; height=&quot;98.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;121.500000&quot; y=&quot;1130.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;121.500000&quot; dy=&quot;0.000000&quot;&gt;Clustered Index&lt;/tspan&gt;&lt;tspan x=&quot;121.500000&quot; dy=&quot;17.666667&quot;&gt;Leaf nodes contain full rows&lt;/tspan&gt;&lt;tspan x=&quot;121.500000&quot; dy=&quot;17.666667&quot;&gt;Data sorted by key&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;U0k=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;303.000000&quot; y=&quot;1092.000000&quot; width=&quot;234.000000&quot; height=&quot;98.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;420.000000&quot; y=&quot;1130.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;420.000000&quot; dy=&quot;0.000000&quot;&gt;Secondary Index&lt;/tspan&gt;&lt;tspan x=&quot;420.000000&quot; dy=&quot;17.666667&quot;&gt;Maps values → PK (InnoDB)&lt;/tspan&gt;&lt;tspan x=&quot;420.000000&quot; dy=&quot;17.666667&quot;&gt;or Row IDs (heap)&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFQgLSZndDsgSClbMF0=&quot;&gt;&lt;marker id=&quot;mk-d2-1991294913-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 270.750000 84.000000 C 270.750000 122.000000 270.750000 142.000000 270.750000 178.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1991294913-3488378134)&quot; mask=&quot;url(#d2-1991294913)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEggLSZndDsgUClbMF0=&quot;&gt;&lt;path d=&quot;M 270.750000 266.000000 C 270.750000 304.000000 270.750000 324.000000 270.750000 360.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1991294913-3488378134)&quot; mask=&quot;url(#d2-1991294913)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KFAgLSZndDsgUilbMF0=&quot;&gt;&lt;path d=&quot;M 270.750000 448.000000 C 270.750000 486.000000 270.750000 506.000000 270.750000 542.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1991294913-3488378134)&quot; mask=&quot;url(#d2-1991294913)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KFIgLSZndDsgUklEKVswXQ==&quot;&gt;&lt;path d=&quot;M 270.750000 630.000000 C 270.750000 668.000000 270.750000 688.000000 270.750000 724.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1991294913-3488378134)&quot; mask=&quot;url(#d2-1991294913)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KFJJRCAtJmd0OyBJWClbMF0=&quot;&gt;&lt;path d=&quot;M 270.750000 812.000000 C 270.750000 850.000000 270.750000 870.000000 270.750000 906.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1991294913-3488378134)&quot; mask=&quot;url(#d2-1991294913)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KElYIC0mZ3Q7IENJKVswXQ==&quot;&gt;&lt;path d=&quot;M 201.792401 993.041203 C 137.899002 1032.000000 121.500000 1052.000000 121.500000 1088.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1991294913-3488378134)&quot; mask=&quot;url(#d2-1991294913)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KElYIC0mZ3Q7IFNJKVswXQ==&quot;&gt;&lt;path d=&quot;M 339.707592 993.041215 C 403.600006 1032.000000 420.000000 1052.000000 420.000000 1088.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1991294913-3488378134)&quot; mask=&quot;url(#d2-1991294913)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;mask id=&quot;d2-1991294913&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;587&quot; height=&quot;1240&quot;&gt;
&lt;rect x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;587&quot; height=&quot;1240&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;

&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;hr&gt;
&lt;h2 id=&quot;related-reading&quot;&gt;Related reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/btrees-and-bplus-trees/&quot;&gt;B-Trees and B+ Trees&lt;/a&gt; — the data structure that powers nearly every index in this post.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/database-normalization/&quot;&gt;Database Normalization&lt;/a&gt; — the logical model these physical structures support.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/postgres-indexing/&quot;&gt;PostgreSQL Indexing Deep Dive&lt;/a&gt; — applies the heap/clustered/secondary distinction to a real database.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/postgres-explain/&quot;&gt;Reading PostgreSQL EXPLAIN Output&lt;/a&gt; — see these structures show up in real query plans.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/postgres-partitioning/&quot;&gt;Postgres Partitioning: Strategies, Advantages, and Pitfalls&lt;/a&gt; — how heap files and TIDs split across multiple physical tables.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;key-takeaways&quot;&gt;Key Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pages&lt;/strong&gt; are the unit of I/O. Indexes reduce the number of pages read; they don’t make individual page reads faster.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Heaps&lt;/strong&gt; store rows in insertion order. Without an index, finding a row requires reading every page.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Row IDs&lt;/strong&gt; (ctid, ROWID, RID) are physical addresses. They are what B-tree indexes store to bridge the index and the heap.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;clustered index&lt;/strong&gt; stores the actual rows in the B-tree leaf nodes. The leaf level is the table. There is no heap.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;primary key&lt;/strong&gt; is a logical uniqueness constraint. Whether it becomes a clustered index depends on the database: always in InnoDB, by default in SQL Server, never in PostgreSQL.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Secondary indexes&lt;/strong&gt; on a clustered table store the primary key value, not a physical address, to stay stable across page splits — at the cost of a double lookup.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;covering index&lt;/strong&gt; avoids the second lookup entirely by including all the columns a query needs directly in the index.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The next time you wonder whether to add an index, you’re really asking: is it worth the cost of maintaining a separate B-tree and potentially doing a second lookup, in exchange for skipping a sequential scan of all those pages?&lt;/p&gt;</content:encoded></item><item><title>ACID, Read Phenomena, and Isolation Levels: What to Use When</title><link>https://abhimanyunagurkar.com/blog/acid-properties-and-isolation-levels/</link><guid isPermaLink="true">https://abhimanyunagurkar.com/blog/acid-properties-and-isolation-levels/</guid><description>A practical guide to database transactions — ACID, five concurrency anomalies, isolation levels, MVCC vs locks, and choosing the right level.</description><pubDate>Sun, 19 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Most concurrency bugs in production aren’t application bugs — they’re isolation bugs. Two requests arrive at the same instant, both read the same row, both update it, and one update silently disappears. Or a customer is shown a price that’s stale by 50 milliseconds and gets charged a different amount. Or a hotel room gets double-booked because two transactions saw “one room available” at the same time.&lt;/p&gt;
&lt;p&gt;The fix isn’t more retries or better logging. It’s understanding what your database actually guarantees, what it doesn’t, and what knobs let you trade one for the other. This post walks through ACID, the five concurrency anomalies you’ll meet in production, the four SQL isolation levels and what each one costs you, how Postgres implements them, and a decision tree for picking the right level — without paying for &lt;code&gt;SERIALIZABLE&lt;/code&gt; everywhere.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-vocabulary&quot;&gt;The Vocabulary&lt;/h2&gt;
&lt;p&gt;Before any code, the words. Most isolation-level confusion comes from these terms being used loosely.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Transaction&lt;/strong&gt; — a unit of work grouping one or more operations into a single logical action. Either all succeed (&lt;code&gt;COMMIT&lt;/code&gt;) or none do (&lt;code&gt;ROLLBACK&lt;/code&gt;). Started with &lt;code&gt;BEGIN&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ACID&lt;/strong&gt; — the four guarantees a “safe” transaction provides: &lt;strong&gt;Atomicity&lt;/strong&gt; (all-or-nothing), &lt;strong&gt;Consistency&lt;/strong&gt; (constraints hold), &lt;strong&gt;Isolation&lt;/strong&gt; (no interference with concurrent transactions), &lt;strong&gt;Durability&lt;/strong&gt; (committed data survives crashes).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Read phenomenon&lt;/strong&gt; — a specific kind of anomaly that becomes possible when isolation is relaxed. Dirty reads, non-repeatable reads, phantom reads, lost updates, write skew — each one a real bug pattern, named after the SQL standard’s classification.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Isolation level&lt;/strong&gt; — the dial controlling which phenomena your transactions are allowed to observe. Higher level = fewer anomalies = more contention. Four standard levels: Read Uncommitted, Read Committed, Repeatable Read, Serializable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;MVCC (Multi-Version Concurrency Control)&lt;/strong&gt; — the mechanism that lets readers and writers not block each other. Every row keeps multiple versions; each transaction sees the version that was committed when it started. Used by Postgres, MySQL InnoDB, Oracle.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Snapshot&lt;/strong&gt; — a point-in-time view of the database visible only to one transaction. Under MVCC, every transaction operates against its own snapshot. Reads inside the transaction stay consistent even as other transactions commit.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lock&lt;/strong&gt; — a database-managed token a transaction holds on a resource (row, range, table) to control concurrent access. &lt;strong&gt;Shared (read) locks&lt;/strong&gt; allow other readers but block writers. &lt;strong&gt;Exclusive (write) locks&lt;/strong&gt; block everyone else. &lt;strong&gt;Predicate locks&lt;/strong&gt; cover a query condition (&lt;code&gt;WHERE status = &apos;available&apos;&lt;/code&gt;), not just specific rows.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SSI (Serializable Snapshot Isolation)&lt;/strong&gt; — Postgres’s implementation of &lt;code&gt;SERIALIZABLE&lt;/code&gt;. Tracks read-write dependency cycles between concurrent transactions and aborts the one that would cause an anomaly, instead of blocking them with predicate locks. Cheaper than classical serializable, but you must handle serialization-failure errors and retry.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pessimistic vs optimistic concurrency control&lt;/strong&gt; — pessimistic locks resources up front (&lt;code&gt;SELECT … FOR UPDATE&lt;/code&gt;). Optimistic doesn’t lock, but checks at commit time whether the data you read has been modified by someone else, and retries if so. Pessimistic is safer under contention; optimistic is faster when contention is rare.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;WAL (Write-Ahead Log)&lt;/strong&gt; — every change is appended to a log file before the in-memory page is touched. Durability comes from &lt;code&gt;fsync&lt;/code&gt;’ing the WAL before &lt;code&gt;COMMIT&lt;/code&gt; returns success. Recovery replays the WAL from the last checkpoint.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;acid-briefly&quot;&gt;ACID, Briefly&lt;/h2&gt;
&lt;p&gt;The four properties, in one paragraph each.&lt;/p&gt;
&lt;h3 id=&quot;atomicity--all-or-nothing&quot;&gt;Atomicity — all-or-nothing&lt;/h3&gt;
&lt;p&gt;Every operation inside a transaction is committed together, or the entire transaction is rolled back on failure. Alice transfers $500 to Bob:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;BEGIN&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  UPDATE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; accounts &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; balance &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; balance &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 500&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;alice&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  UPDATE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; accounts &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; balance &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; balance &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 500&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;bob&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;COMMIT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the server crashes after the first &lt;code&gt;UPDATE&lt;/code&gt; but before the second, atomicity ensures the rollback on recovery restores Alice’s balance. Money never disappears mid-transfer.&lt;/p&gt;
&lt;h3 id=&quot;consistency--constraints-hold&quot;&gt;Consistency — constraints hold&lt;/h3&gt;
&lt;p&gt;Every transaction must leave the database satisfying all declared rules — foreign keys, unique constraints, &lt;code&gt;CHECK&lt;/code&gt; constraints, triggers. If Alice has $200 and a debit of $500 would violate &lt;code&gt;CHECK (balance &gt;= 0)&lt;/code&gt;, the entire transaction is rejected. No partial state, no application bypass.&lt;/p&gt;
&lt;h3 id=&quot;isolation--concurrent-transactions-dont-interfere&quot;&gt;Isolation — concurrent transactions don’t interfere&lt;/h3&gt;
&lt;p&gt;This is the most nuanced of the four. Full isolation is expensive, so databases let you tune it via &lt;strong&gt;isolation levels&lt;/strong&gt;. The rest of this post is mostly about this property.&lt;/p&gt;
&lt;h3 id=&quot;durability--committed-data-survives-crashes&quot;&gt;Durability — committed data survives crashes&lt;/h3&gt;
&lt;p&gt;Once &lt;code&gt;COMMIT&lt;/code&gt; returns success, the change is persisted to disk via the WAL, even if the power cuts out a millisecond later. This is why commits have an I/O cost — durability isn’t free.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-five-read-phenomena&quot;&gt;The Five Read Phenomena&lt;/h2&gt;
&lt;p&gt;When isolation is relaxed, transactions can observe these anomalies. The SQL standard names three; two more (lost update and write skew) are real bugs you’ll hit in practice that don’t appear in the original definitions.&lt;/p&gt;
&lt;h3 id=&quot;1-dirty-read&quot;&gt;1. Dirty Read&lt;/h3&gt;
&lt;p&gt;A transaction reads data written by another transaction that has not yet committed. If the writer rolls back, the reader has acted on data that never officially existed.&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.6.9&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 1026 1096&quot;&gt;&lt;svg class=&quot;d2-3531704930 d2-svg&quot; width=&quot;1026&quot; height=&quot;1096&quot; viewBox=&quot;-13 27 1026 1096&quot;&gt;&lt;rect x=&quot;-13.000000&quot; y=&quot;27.000000&quot; width=&quot;1026.000000&quot; height=&quot;1096.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-3531704930 .text {
	font-family: &quot;d2-3531704930-font-regular&quot;;
}
@font-face {
	font-family: d2-3531704930-font-regular;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-3531704930 .text-italic {
	font-family: &quot;d2-3531704930-font-italic&quot;;
}
@font-face {
	font-family: d2-3531704930-font-italic;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-3531704930 .fill-N1{fill:#0A0F25;}
		.d2-3531704930 .fill-N2{fill:#676C7E;}
		.d2-3531704930 .fill-N3{fill:#9499AB;}
		.d2-3531704930 .fill-N4{fill:#CFD2DD;}
		.d2-3531704930 .fill-N5{fill:#DEE1EB;}
		.d2-3531704930 .fill-N6{fill:#EEF1F8;}
		.d2-3531704930 .fill-N7{fill:#FFFFFF;}
		.d2-3531704930 .fill-B1{fill:#0D32B2;}
		.d2-3531704930 .fill-B2{fill:#0D32B2;}
		.d2-3531704930 .fill-B3{fill:#E3E9FD;}
		.d2-3531704930 .fill-B4{fill:#E3E9FD;}
		.d2-3531704930 .fill-B5{fill:#EDF0FD;}
		.d2-3531704930 .fill-B6{fill:#F7F8FE;}
		.d2-3531704930 .fill-AA2{fill:#4A6FF3;}
		.d2-3531704930 .fill-AA4{fill:#EDF0FD;}
		.d2-3531704930 .fill-AA5{fill:#F7F8FE;}
		.d2-3531704930 .fill-AB4{fill:#EDF0FD;}
		.d2-3531704930 .fill-AB5{fill:#F7F8FE;}
		.d2-3531704930 .stroke-N1{stroke:#0A0F25;}
		.d2-3531704930 .stroke-N2{stroke:#676C7E;}
		.d2-3531704930 .stroke-N3{stroke:#9499AB;}
		.d2-3531704930 .stroke-N4{stroke:#CFD2DD;}
		.d2-3531704930 .stroke-N5{stroke:#DEE1EB;}
		.d2-3531704930 .stroke-N6{stroke:#EEF1F8;}
		.d2-3531704930 .stroke-N7{stroke:#FFFFFF;}
		.d2-3531704930 .stroke-B1{stroke:#0D32B2;}
		.d2-3531704930 .stroke-B2{stroke:#0D32B2;}
		.d2-3531704930 .stroke-B3{stroke:#E3E9FD;}
		.d2-3531704930 .stroke-B4{stroke:#E3E9FD;}
		.d2-3531704930 .stroke-B5{stroke:#EDF0FD;}
		.d2-3531704930 .stroke-B6{stroke:#F7F8FE;}
		.d2-3531704930 .stroke-AA2{stroke:#4A6FF3;}
		.d2-3531704930 .stroke-AA4{stroke:#EDF0FD;}
		.d2-3531704930 .stroke-AA5{stroke:#F7F8FE;}
		.d2-3531704930 .stroke-AB4{stroke:#EDF0FD;}
		.d2-3531704930 .stroke-AB5{stroke:#F7F8FE;}
		.d2-3531704930 .background-color-N1{background-color:#0A0F25;}
		.d2-3531704930 .background-color-N2{background-color:#676C7E;}
		.d2-3531704930 .background-color-N3{background-color:#9499AB;}
		.d2-3531704930 .background-color-N4{background-color:#CFD2DD;}
		.d2-3531704930 .background-color-N5{background-color:#DEE1EB;}
		.d2-3531704930 .background-color-N6{background-color:#EEF1F8;}
		.d2-3531704930 .background-color-N7{background-color:#FFFFFF;}
		.d2-3531704930 .background-color-B1{background-color:#0D32B2;}
		.d2-3531704930 .background-color-B2{background-color:#0D32B2;}
		.d2-3531704930 .background-color-B3{background-color:#E3E9FD;}
		.d2-3531704930 .background-color-B4{background-color:#E3E9FD;}
		.d2-3531704930 .background-color-B5{background-color:#EDF0FD;}
		.d2-3531704930 .background-color-B6{background-color:#F7F8FE;}
		.d2-3531704930 .background-color-AA2{background-color:#4A6FF3;}
		.d2-3531704930 .background-color-AA4{background-color:#EDF0FD;}
		.d2-3531704930 .background-color-AA5{background-color:#F7F8FE;}
		.d2-3531704930 .background-color-AB4{background-color:#EDF0FD;}
		.d2-3531704930 .background-color-AB5{background-color:#F7F8FE;}
		.d2-3531704930 .color-N1{color:#0A0F25;}
		.d2-3531704930 .color-N2{color:#676C7E;}
		.d2-3531704930 .color-N3{color:#9499AB;}
		.d2-3531704930 .color-N4{color:#CFD2DD;}
		.d2-3531704930 .color-N5{color:#DEE1EB;}
		.d2-3531704930 .color-N6{color:#EEF1F8;}
		.d2-3531704930 .color-N7{color:#FFFFFF;}
		.d2-3531704930 .color-B1{color:#0D32B2;}
		.d2-3531704930 .color-B2{color:#0D32B2;}
		.d2-3531704930 .color-B3{color:#E3E9FD;}
		.d2-3531704930 .color-B4{color:#E3E9FD;}
		.d2-3531704930 .color-B5{color:#EDF0FD;}
		.d2-3531704930 .color-B6{color:#F7F8FE;}
		.d2-3531704930 .color-AA2{color:#4A6FF3;}
		.d2-3531704930 .color-AA4{color:#EDF0FD;}
		.d2-3531704930 .color-AA5{color:#F7F8FE;}
		.d2-3531704930 .color-AB4{color:#EDF0FD;}
		.d2-3531704930 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-3531704930);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-3531704930);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-3531704930);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-3531704930);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-3531704930);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-3531704930);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-3531704930);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-3531704930);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-3531704930);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-3531704930);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-3531704930);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-3531704930);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-3531704930);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-3531704930);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-3531704930);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-3531704930);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-3531704930);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-3531704930);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;QQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;12.000000&quot; y=&quot;52.000000&quot; width=&quot;178.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;101.000000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Txn A (Travel Agent)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;REI=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;388.000000&quot; y=&quot;52.000000&quot; width=&quot;107.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;441.500000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Database&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Qg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;587.000000&quot; y=&quot;52.000000&quot; width=&quot;189.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;681.500000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Txn B (Reporting Job)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLS0gKVswXQ==&quot;&gt;&lt;path d=&quot;M 101.000000 120.000000 L 101.000000 1097.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-3531704930)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KERCIC0tIClbMF0=&quot;&gt;&lt;path d=&quot;M 441.500000 120.000000 L 441.500000 1097.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-3531704930)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLS0gKVswXQ==&quot;&gt;&lt;path d=&quot;M 681.500000 120.000000 L 681.500000 1097.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-3531704930)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgREIpWzBd&quot;&gt;&lt;marker id=&quot;mk-d2-3531704930-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 103.000000 198.000000 L 437.500000 198.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3531704930-3488378134)&quot; mask=&quot;url(#d2-3531704930)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;271.500000&quot; y=&quot;204.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;BEGIN&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgREIpWzFd&quot;&gt;&lt;path d=&quot;M 103.000000 288.000000 L 437.500000 288.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3531704930-3488378134)&quot; mask=&quot;url(#d2-3531704930)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;271.000000&quot; y=&quot;294.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;UPDATE seats_available = 0 (uncommitted)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgREIpWzBd&quot;&gt;&lt;path d=&quot;M 679.500000 378.000000 L 445.500000 378.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3531704930-3488378134)&quot; mask=&quot;url(#d2-3531704930)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;561.500000&quot; y=&quot;384.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;BEGIN&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgREIpWzFd&quot;&gt;&lt;path d=&quot;M 679.500000 468.000000 L 445.500000 468.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3531704930-3488378134)&quot; mask=&quot;url(#d2-3531704930)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;562.000000&quot; y=&quot;474.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;SELECT seats_available → 0&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgQilbMF0=&quot;&gt;&lt;path d=&quot;M 683.500000 548.000000 L 789.000000 548.000000 S 799.000000 548.000000 799.000000 558.000000 L 799.000000 583.000000 S 799.000000 593.000000 789.000000 593.000000 L 685.500000 593.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3531704930-3488378134)&quot; mask=&quot;url(#d2-3531704930)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;799.500000&quot; y=&quot;576.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Dirty read! Reports &quot;Flight is full&quot;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgQSlbMF0=&quot;&gt;&lt;path d=&quot;M 103.000000 663.000000 L 193.000000 663.000000 S 203.000000 663.000000 203.000000 673.000000 L 203.000000 698.000000 S 203.000000 708.000000 193.000000 708.000000 L 105.000000 708.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3531704930-3488378134)&quot; mask=&quot;url(#d2-3531704930)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;203.000000&quot; y=&quot;691.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Payment gateway times out&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgREIpWzJd&quot;&gt;&lt;path d=&quot;M 103.000000 788.000000 L 437.500000 788.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3531704930-3488378134)&quot; mask=&quot;url(#d2-3531704930)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;271.500000&quot; y=&quot;794.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;ROLLBACK&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KERCIC0mZ3Q7IERCKVswXQ==&quot;&gt;&lt;path d=&quot;M 443.500000 868.000000 L 536.000000 868.000000 S 546.000000 868.000000 546.000000 878.000000 L 546.000000 903.000000 S 546.000000 913.000000 536.000000 913.000000 L 445.500000 913.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3531704930-3488378134)&quot; mask=&quot;url(#d2-3531704930)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;546.500000&quot; y=&quot;896.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;seats_available restored to 1&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgQilbMV0=&quot;&gt;&lt;path d=&quot;M 683.500000 983.000000 L 830.000000 983.000000 S 840.000000 983.000000 840.000000 993.000000 L 840.000000 1018.000000 S 840.000000 1028.000000 830.000000 1028.000000 L 685.500000 1028.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-3531704930-3488378134)&quot; mask=&quot;url(#d2-3531704930)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;840.500000&quot; y=&quot;1011.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;B already told the customer the flight was full&lt;/text&gt;&lt;/g&gt;&lt;mask id=&quot;d2-3531704930&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-13&quot; y=&quot;27&quot; width=&quot;1026&quot; height=&quot;1096&quot;&gt;
&lt;rect x=&quot;-13&quot; y=&quot;27&quot; width=&quot;1026&quot; height=&quot;1096&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;34.500000&quot; y=&quot;74.500000&quot; width=&quot;133&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;410.500000&quot; y=&quot;74.500000&quot; width=&quot;62&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;609.500000&quot; y=&quot;74.500000&quot; width=&quot;144&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;251.000000&quot; y=&quot;188.000000&quot; width=&quot;41&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;131.000000&quot; y=&quot;278.000000&quot; width=&quot;280&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;541.000000&quot; y=&quot;368.000000&quot; width=&quot;41&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;472.000000&quot; y=&quot;458.000000&quot; width=&quot;180&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;692.000000&quot; y=&quot;560.000000&quot; width=&quot;215&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;111.000000&quot; y=&quot;675.000000&quot; width=&quot;184&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;236.000000&quot; y=&quot;778.000000&quot; width=&quot;71&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;452.000000&quot; y=&quot;880.000000&quot; width=&quot;189&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;692.000000&quot; y=&quot;995.000000&quot; width=&quot;297&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;Transaction B read a value that was rolled back. The seat was available all along — but the customer was already told it wasn’t.&lt;/p&gt;
&lt;h3 id=&quot;2-non-repeatable-read&quot;&gt;2. Non-Repeatable Read&lt;/h3&gt;
&lt;p&gt;A transaction reads the same row twice and gets different values, because another committed transaction modified that row in between.&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.6.9&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 1037 1161&quot;&gt;&lt;svg class=&quot;d2-1010634437 d2-svg&quot; width=&quot;1037&quot; height=&quot;1161&quot; viewBox=&quot;-13 27 1037 1161&quot;&gt;&lt;rect x=&quot;-13.000000&quot; y=&quot;27.000000&quot; width=&quot;1037.000000&quot; height=&quot;1161.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-1010634437 .text {
	font-family: &quot;d2-1010634437-font-regular&quot;;
}
@font-face {
	font-family: d2-1010634437-font-regular;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-1010634437 .text-italic {
	font-family: &quot;d2-1010634437-font-italic&quot;;
}
@font-face {
	font-family: d2-1010634437-font-italic;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-1010634437 .fill-N1{fill:#0A0F25;}
		.d2-1010634437 .fill-N2{fill:#676C7E;}
		.d2-1010634437 .fill-N3{fill:#9499AB;}
		.d2-1010634437 .fill-N4{fill:#CFD2DD;}
		.d2-1010634437 .fill-N5{fill:#DEE1EB;}
		.d2-1010634437 .fill-N6{fill:#EEF1F8;}
		.d2-1010634437 .fill-N7{fill:#FFFFFF;}
		.d2-1010634437 .fill-B1{fill:#0D32B2;}
		.d2-1010634437 .fill-B2{fill:#0D32B2;}
		.d2-1010634437 .fill-B3{fill:#E3E9FD;}
		.d2-1010634437 .fill-B4{fill:#E3E9FD;}
		.d2-1010634437 .fill-B5{fill:#EDF0FD;}
		.d2-1010634437 .fill-B6{fill:#F7F8FE;}
		.d2-1010634437 .fill-AA2{fill:#4A6FF3;}
		.d2-1010634437 .fill-AA4{fill:#EDF0FD;}
		.d2-1010634437 .fill-AA5{fill:#F7F8FE;}
		.d2-1010634437 .fill-AB4{fill:#EDF0FD;}
		.d2-1010634437 .fill-AB5{fill:#F7F8FE;}
		.d2-1010634437 .stroke-N1{stroke:#0A0F25;}
		.d2-1010634437 .stroke-N2{stroke:#676C7E;}
		.d2-1010634437 .stroke-N3{stroke:#9499AB;}
		.d2-1010634437 .stroke-N4{stroke:#CFD2DD;}
		.d2-1010634437 .stroke-N5{stroke:#DEE1EB;}
		.d2-1010634437 .stroke-N6{stroke:#EEF1F8;}
		.d2-1010634437 .stroke-N7{stroke:#FFFFFF;}
		.d2-1010634437 .stroke-B1{stroke:#0D32B2;}
		.d2-1010634437 .stroke-B2{stroke:#0D32B2;}
		.d2-1010634437 .stroke-B3{stroke:#E3E9FD;}
		.d2-1010634437 .stroke-B4{stroke:#E3E9FD;}
		.d2-1010634437 .stroke-B5{stroke:#EDF0FD;}
		.d2-1010634437 .stroke-B6{stroke:#F7F8FE;}
		.d2-1010634437 .stroke-AA2{stroke:#4A6FF3;}
		.d2-1010634437 .stroke-AA4{stroke:#EDF0FD;}
		.d2-1010634437 .stroke-AA5{stroke:#F7F8FE;}
		.d2-1010634437 .stroke-AB4{stroke:#EDF0FD;}
		.d2-1010634437 .stroke-AB5{stroke:#F7F8FE;}
		.d2-1010634437 .background-color-N1{background-color:#0A0F25;}
		.d2-1010634437 .background-color-N2{background-color:#676C7E;}
		.d2-1010634437 .background-color-N3{background-color:#9499AB;}
		.d2-1010634437 .background-color-N4{background-color:#CFD2DD;}
		.d2-1010634437 .background-color-N5{background-color:#DEE1EB;}
		.d2-1010634437 .background-color-N6{background-color:#EEF1F8;}
		.d2-1010634437 .background-color-N7{background-color:#FFFFFF;}
		.d2-1010634437 .background-color-B1{background-color:#0D32B2;}
		.d2-1010634437 .background-color-B2{background-color:#0D32B2;}
		.d2-1010634437 .background-color-B3{background-color:#E3E9FD;}
		.d2-1010634437 .background-color-B4{background-color:#E3E9FD;}
		.d2-1010634437 .background-color-B5{background-color:#EDF0FD;}
		.d2-1010634437 .background-color-B6{background-color:#F7F8FE;}
		.d2-1010634437 .background-color-AA2{background-color:#4A6FF3;}
		.d2-1010634437 .background-color-AA4{background-color:#EDF0FD;}
		.d2-1010634437 .background-color-AA5{background-color:#F7F8FE;}
		.d2-1010634437 .background-color-AB4{background-color:#EDF0FD;}
		.d2-1010634437 .background-color-AB5{background-color:#F7F8FE;}
		.d2-1010634437 .color-N1{color:#0A0F25;}
		.d2-1010634437 .color-N2{color:#676C7E;}
		.d2-1010634437 .color-N3{color:#9499AB;}
		.d2-1010634437 .color-N4{color:#CFD2DD;}
		.d2-1010634437 .color-N5{color:#DEE1EB;}
		.d2-1010634437 .color-N6{color:#EEF1F8;}
		.d2-1010634437 .color-N7{color:#FFFFFF;}
		.d2-1010634437 .color-B1{color:#0D32B2;}
		.d2-1010634437 .color-B2{color:#0D32B2;}
		.d2-1010634437 .color-B3{color:#E3E9FD;}
		.d2-1010634437 .color-B4{color:#E3E9FD;}
		.d2-1010634437 .color-B5{color:#EDF0FD;}
		.d2-1010634437 .color-B6{color:#F7F8FE;}
		.d2-1010634437 .color-AA2{color:#4A6FF3;}
		.d2-1010634437 .color-AA4{color:#EDF0FD;}
		.d2-1010634437 .color-AA5{color:#F7F8FE;}
		.d2-1010634437 .color-AB4{color:#EDF0FD;}
		.d2-1010634437 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-1010634437);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-1010634437);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-1010634437);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-1010634437);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-1010634437);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-1010634437);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-1010634437);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-1010634437);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-1010634437);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-1010634437);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-1010634437);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-1010634437);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-1010634437);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-1010634437);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-1010634437);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-1010634437);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-1010634437);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-1010634437);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;QQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;12.000000&quot; y=&quot;52.000000&quot; width=&quot;208.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;116.000000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Txn A (Order Processing)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;REI=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;447.000000&quot; y=&quot;52.000000&quot; width=&quot;107.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;500.500000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Database&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Qg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;771.000000&quot; y=&quot;52.000000&quot; width=&quot;228.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;885.000000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Txn B (Admin Price Update)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLS0gKVswXQ==&quot;&gt;&lt;path d=&quot;M 116.000000 120.000000 L 116.000000 1162.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-1010634437)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KERCIC0tIClbMF0=&quot;&gt;&lt;path d=&quot;M 500.500000 120.000000 L 500.500000 1162.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-1010634437)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLS0gKVswXQ==&quot;&gt;&lt;path d=&quot;M 885.000000 120.000000 L 885.000000 1162.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-1010634437)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgREIpWzBd&quot;&gt;&lt;marker id=&quot;mk-d2-1010634437-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 118.000000 198.000000 L 496.500000 198.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1010634437-3488378134)&quot; mask=&quot;url(#d2-1010634437)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;308.500000&quot; y=&quot;204.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;BEGIN&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgREIpWzFd&quot;&gt;&lt;path d=&quot;M 118.000000 288.000000 L 496.500000 288.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1010634437-3488378134)&quot; mask=&quot;url(#d2-1010634437)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;308.500000&quot; y=&quot;294.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;SELECT price WHERE product=&apos;LAPTOP-X&apos; → $999&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgQSlbMF0=&quot;&gt;&lt;path d=&quot;M 118.000000 368.000000 L 201.500000 368.000000 S 211.500000 368.000000 211.500000 378.000000 L 211.500000 403.000000 S 211.500000 413.000000 201.500000 413.000000 L 120.000000 413.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1010634437-3488378134)&quot; mask=&quot;url(#d2-1010634437)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;211.500000&quot; y=&quot;396.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Displays $999 to customer&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgREIpWzBd&quot;&gt;&lt;path d=&quot;M 883.000000 493.000000 L 504.500000 493.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1010634437-3488378134)&quot; mask=&quot;url(#d2-1010634437)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;692.500000&quot; y=&quot;499.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;BEGIN&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgREIpWzFd&quot;&gt;&lt;path d=&quot;M 883.000000 583.000000 L 504.500000 583.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1010634437-3488378134)&quot; mask=&quot;url(#d2-1010634437)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;692.500000&quot; y=&quot;589.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;UPDATE price = $1199 WHERE product=&apos;LAPTOP-X&apos;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgREIpWzJd&quot;&gt;&lt;path d=&quot;M 883.000000 673.000000 L 504.500000 673.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1010634437-3488378134)&quot; mask=&quot;url(#d2-1010634437)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;693.000000&quot; y=&quot;679.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;COMMIT&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgREIpWzJd&quot;&gt;&lt;path d=&quot;M 118.000000 763.000000 L 496.500000 763.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1010634437-3488378134)&quot; mask=&quot;url(#d2-1010634437)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;308.000000&quot; y=&quot;769.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;SELECT price WHERE product=&apos;LAPTOP-X&apos; → $1199&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgQSlbMV0=&quot;&gt;&lt;path d=&quot;M 118.000000 843.000000 L 198.500000 843.000000 S 208.500000 843.000000 208.500000 853.000000 L 208.500000 878.000000 S 208.500000 888.000000 198.500000 888.000000 L 120.000000 888.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1010634437-3488378134)&quot; mask=&quot;url(#d2-1010634437)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;208.500000&quot; y=&quot;871.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Charges customer $1199!&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgREIpWzNd&quot;&gt;&lt;path d=&quot;M 118.000000 968.000000 L 496.500000 968.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1010634437-3488378134)&quot; mask=&quot;url(#d2-1010634437)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;308.000000&quot; y=&quot;974.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;COMMIT&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgQSlbMl0=&quot;&gt;&lt;path d=&quot;M 118.000000 1048.000000 L 246.000000 1048.000000 S 256.000000 1048.000000 256.000000 1058.000000 L 256.000000 1083.000000 S 256.000000 1093.000000 246.000000 1093.000000 L 120.000000 1093.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1010634437-3488378134)&quot; mask=&quot;url(#d2-1010634437)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;256.000000&quot; y=&quot;1076.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Customer saw $999, was charged $1199&lt;/text&gt;&lt;/g&gt;&lt;mask id=&quot;d2-1010634437&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-13&quot; y=&quot;27&quot; width=&quot;1037&quot; height=&quot;1161&quot;&gt;
&lt;rect x=&quot;-13&quot; y=&quot;27&quot; width=&quot;1037&quot; height=&quot;1161&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;34.500000&quot; y=&quot;74.500000&quot; width=&quot;163&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;469.500000&quot; y=&quot;74.500000&quot; width=&quot;62&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;793.500000&quot; y=&quot;74.500000&quot; width=&quot;183&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;288.000000&quot; y=&quot;188.000000&quot; width=&quot;41&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;150.000000&quot; y=&quot;278.000000&quot; width=&quot;317&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;126.000000&quot; y=&quot;380.000000&quot; width=&quot;171&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;672.000000&quot; y=&quot;483.000000&quot; width=&quot;41&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;530.000000&quot; y=&quot;573.000000&quot; width=&quot;325&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;665.000000&quot; y=&quot;663.000000&quot; width=&quot;56&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;146.000000&quot; y=&quot;753.000000&quot; width=&quot;324&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;126.000000&quot; y=&quot;855.000000&quot; width=&quot;165&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;280.000000&quot; y=&quot;958.000000&quot; width=&quot;56&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;126.000000&quot; y=&quot;1060.000000&quot; width=&quot;260&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;Same row, same transaction, two different values. Causes silent billing discrepancies that only surface in customer complaints.&lt;/p&gt;
&lt;h3 id=&quot;3-phantom-read&quot;&gt;3. Phantom Read&lt;/h3&gt;
&lt;p&gt;A transaction re-executes a query with a filter and gets a different set of rows — not because existing rows changed, but because another transaction inserted or deleted matching rows.&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.6.9&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 908 1126&quot;&gt;&lt;svg class=&quot;d2-4157135275 d2-svg&quot; width=&quot;908&quot; height=&quot;1126&quot; viewBox=&quot;-13 27 908 1126&quot;&gt;&lt;rect x=&quot;-13.000000&quot; y=&quot;27.000000&quot; width=&quot;908.000000&quot; height=&quot;1126.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-4157135275 .text {
	font-family: &quot;d2-4157135275-font-regular&quot;;
}
@font-face {
	font-family: d2-4157135275-font-regular;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-4157135275 .text-italic {
	font-family: &quot;d2-4157135275-font-italic&quot;;
}
@font-face {
	font-family: d2-4157135275-font-italic;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-4157135275 .fill-N1{fill:#0A0F25;}
		.d2-4157135275 .fill-N2{fill:#676C7E;}
		.d2-4157135275 .fill-N3{fill:#9499AB;}
		.d2-4157135275 .fill-N4{fill:#CFD2DD;}
		.d2-4157135275 .fill-N5{fill:#DEE1EB;}
		.d2-4157135275 .fill-N6{fill:#EEF1F8;}
		.d2-4157135275 .fill-N7{fill:#FFFFFF;}
		.d2-4157135275 .fill-B1{fill:#0D32B2;}
		.d2-4157135275 .fill-B2{fill:#0D32B2;}
		.d2-4157135275 .fill-B3{fill:#E3E9FD;}
		.d2-4157135275 .fill-B4{fill:#E3E9FD;}
		.d2-4157135275 .fill-B5{fill:#EDF0FD;}
		.d2-4157135275 .fill-B6{fill:#F7F8FE;}
		.d2-4157135275 .fill-AA2{fill:#4A6FF3;}
		.d2-4157135275 .fill-AA4{fill:#EDF0FD;}
		.d2-4157135275 .fill-AA5{fill:#F7F8FE;}
		.d2-4157135275 .fill-AB4{fill:#EDF0FD;}
		.d2-4157135275 .fill-AB5{fill:#F7F8FE;}
		.d2-4157135275 .stroke-N1{stroke:#0A0F25;}
		.d2-4157135275 .stroke-N2{stroke:#676C7E;}
		.d2-4157135275 .stroke-N3{stroke:#9499AB;}
		.d2-4157135275 .stroke-N4{stroke:#CFD2DD;}
		.d2-4157135275 .stroke-N5{stroke:#DEE1EB;}
		.d2-4157135275 .stroke-N6{stroke:#EEF1F8;}
		.d2-4157135275 .stroke-N7{stroke:#FFFFFF;}
		.d2-4157135275 .stroke-B1{stroke:#0D32B2;}
		.d2-4157135275 .stroke-B2{stroke:#0D32B2;}
		.d2-4157135275 .stroke-B3{stroke:#E3E9FD;}
		.d2-4157135275 .stroke-B4{stroke:#E3E9FD;}
		.d2-4157135275 .stroke-B5{stroke:#EDF0FD;}
		.d2-4157135275 .stroke-B6{stroke:#F7F8FE;}
		.d2-4157135275 .stroke-AA2{stroke:#4A6FF3;}
		.d2-4157135275 .stroke-AA4{stroke:#EDF0FD;}
		.d2-4157135275 .stroke-AA5{stroke:#F7F8FE;}
		.d2-4157135275 .stroke-AB4{stroke:#EDF0FD;}
		.d2-4157135275 .stroke-AB5{stroke:#F7F8FE;}
		.d2-4157135275 .background-color-N1{background-color:#0A0F25;}
		.d2-4157135275 .background-color-N2{background-color:#676C7E;}
		.d2-4157135275 .background-color-N3{background-color:#9499AB;}
		.d2-4157135275 .background-color-N4{background-color:#CFD2DD;}
		.d2-4157135275 .background-color-N5{background-color:#DEE1EB;}
		.d2-4157135275 .background-color-N6{background-color:#EEF1F8;}
		.d2-4157135275 .background-color-N7{background-color:#FFFFFF;}
		.d2-4157135275 .background-color-B1{background-color:#0D32B2;}
		.d2-4157135275 .background-color-B2{background-color:#0D32B2;}
		.d2-4157135275 .background-color-B3{background-color:#E3E9FD;}
		.d2-4157135275 .background-color-B4{background-color:#E3E9FD;}
		.d2-4157135275 .background-color-B5{background-color:#EDF0FD;}
		.d2-4157135275 .background-color-B6{background-color:#F7F8FE;}
		.d2-4157135275 .background-color-AA2{background-color:#4A6FF3;}
		.d2-4157135275 .background-color-AA4{background-color:#EDF0FD;}
		.d2-4157135275 .background-color-AA5{background-color:#F7F8FE;}
		.d2-4157135275 .background-color-AB4{background-color:#EDF0FD;}
		.d2-4157135275 .background-color-AB5{background-color:#F7F8FE;}
		.d2-4157135275 .color-N1{color:#0A0F25;}
		.d2-4157135275 .color-N2{color:#676C7E;}
		.d2-4157135275 .color-N3{color:#9499AB;}
		.d2-4157135275 .color-N4{color:#CFD2DD;}
		.d2-4157135275 .color-N5{color:#DEE1EB;}
		.d2-4157135275 .color-N6{color:#EEF1F8;}
		.d2-4157135275 .color-N7{color:#FFFFFF;}
		.d2-4157135275 .color-B1{color:#0D32B2;}
		.d2-4157135275 .color-B2{color:#0D32B2;}
		.d2-4157135275 .color-B3{color:#E3E9FD;}
		.d2-4157135275 .color-B4{color:#E3E9FD;}
		.d2-4157135275 .color-B5{color:#EDF0FD;}
		.d2-4157135275 .color-B6{color:#F7F8FE;}
		.d2-4157135275 .color-AA2{color:#4A6FF3;}
		.d2-4157135275 .color-AA4{color:#EDF0FD;}
		.d2-4157135275 .color-AA5{color:#F7F8FE;}
		.d2-4157135275 .color-AB4{color:#EDF0FD;}
		.d2-4157135275 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-4157135275);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-4157135275);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-4157135275);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-4157135275);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-4157135275);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-4157135275);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-4157135275);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-4157135275);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-4157135275);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-4157135275);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-4157135275);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-4157135275);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-4157135275);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-4157135275);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-4157135275);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-4157135275);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-4157135275);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-4157135275);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;QQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;12.000000&quot; y=&quot;52.000000&quot; width=&quot;191.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;107.500000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Txn A (Guest Booking)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;REI=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;423.000000&quot; y=&quot;52.000000&quot; width=&quot;107.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;476.500000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Database&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Qg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;680.000000&quot; y=&quot;52.000000&quot; width=&quot;190.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;775.000000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Txn B (Another Guest)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLS0gKVswXQ==&quot;&gt;&lt;path d=&quot;M 107.500000 120.000000 L 107.500000 1127.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-4157135275)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KERCIC0tIClbMF0=&quot;&gt;&lt;path d=&quot;M 476.500000 120.000000 L 476.500000 1127.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-4157135275)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLS0gKVswXQ==&quot;&gt;&lt;path d=&quot;M 775.000000 120.000000 L 775.000000 1127.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-4157135275)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgREIpWzBd&quot;&gt;&lt;marker id=&quot;mk-d2-4157135275-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 109.500000 198.000000 L 472.500000 198.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-4157135275-3488378134)&quot; mask=&quot;url(#d2-4157135275)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;292.500000&quot; y=&quot;204.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;BEGIN&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgREIpWzFd&quot;&gt;&lt;path d=&quot;M 109.500000 288.000000 L 472.500000 288.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-4157135275-3488378134)&quot; mask=&quot;url(#d2-4157135275)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;292.000000&quot; y=&quot;294.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;SELECT COUNT(*) WHERE status=&apos;available&apos; → 1&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgQSlbMF0=&quot;&gt;&lt;path d=&quot;M 109.500000 368.000000 L 219.000000 368.000000 S 229.000000 368.000000 229.000000 378.000000 L 229.000000 403.000000 S 229.000000 413.000000 219.000000 413.000000 L 111.500000 413.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-4157135275-3488378134)&quot; mask=&quot;url(#d2-4157135275)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;229.500000&quot; y=&quot;396.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;One room left, proceeding to book&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgREIpWzBd&quot;&gt;&lt;path d=&quot;M 773.000000 493.000000 L 480.500000 493.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-4157135275-3488378134)&quot; mask=&quot;url(#d2-4157135275)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;625.500000&quot; y=&quot;499.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;BEGIN&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgREIpWzFd&quot;&gt;&lt;path d=&quot;M 773.000000 583.000000 L 480.500000 583.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-4157135275-3488378134)&quot; mask=&quot;url(#d2-4157135275)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;625.500000&quot; y=&quot;589.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;INSERT booking for ROOM-204&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgREIpWzJd&quot;&gt;&lt;path d=&quot;M 773.000000 673.000000 L 480.500000 673.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-4157135275-3488378134)&quot; mask=&quot;url(#d2-4157135275)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;626.000000&quot; y=&quot;679.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;UPDATE ROOM-204 status = &apos;booked&apos;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgREIpWzNd&quot;&gt;&lt;path d=&quot;M 773.000000 763.000000 L 480.500000 763.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-4157135275-3488378134)&quot; mask=&quot;url(#d2-4157135275)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;626.000000&quot; y=&quot;769.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;COMMIT&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgREIpWzJd&quot;&gt;&lt;path d=&quot;M 109.500000 853.000000 L 472.500000 853.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-4157135275-3488378134)&quot; mask=&quot;url(#d2-4157135275)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;292.500000&quot; y=&quot;859.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;SELECT COUNT(*) WHERE status=&apos;available&apos; → 0&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgQSlbMV0=&quot;&gt;&lt;path d=&quot;M 109.500000 933.000000 L 250.500000 933.000000 S 260.500000 933.000000 260.500000 943.000000 L 260.500000 968.000000 S 260.500000 978.000000 250.500000 978.000000 L 111.500000 978.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-4157135275-3488378134)&quot; mask=&quot;url(#d2-4157135275)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;261.000000&quot; y=&quot;961.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Room vanished — but A already promised it!&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgREIpWzNd&quot;&gt;&lt;path d=&quot;M 109.500000 1058.000000 L 472.500000 1058.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-4157135275-3488378134)&quot; mask=&quot;url(#d2-4157135275)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;292.500000&quot; y=&quot;1064.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;COMMIT (may double-book or error)&lt;/text&gt;&lt;/g&gt;&lt;mask id=&quot;d2-4157135275&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-13&quot; y=&quot;27&quot; width=&quot;908&quot; height=&quot;1126&quot;&gt;
&lt;rect x=&quot;-13&quot; y=&quot;27&quot; width=&quot;908&quot; height=&quot;1126&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;34.500000&quot; y=&quot;74.500000&quot; width=&quot;146&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;445.500000&quot; y=&quot;74.500000&quot; width=&quot;62&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;702.500000&quot; y=&quot;74.500000&quot; width=&quot;145&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;272.000000&quot; y=&quot;188.000000&quot; width=&quot;41&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;138.000000&quot; y=&quot;278.000000&quot; width=&quot;308&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;118.000000&quot; y=&quot;380.000000&quot; width=&quot;223&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;605.000000&quot; y=&quot;483.000000&quot; width=&quot;41&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;527.000000&quot; y=&quot;573.000000&quot; width=&quot;197&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;507.000000&quot; y=&quot;663.000000&quot; width=&quot;238&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;598.000000&quot; y=&quot;753.000000&quot; width=&quot;56&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;138.000000&quot; y=&quot;843.000000&quot; width=&quot;309&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;118.000000&quot; y=&quot;945.000000&quot; width=&quot;286&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;176.000000&quot; y=&quot;1048.000000&quot; width=&quot;233&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;No existing row was modified between Transaction A’s two reads — a new row appeared and changed the result. Especially dangerous in booking, ticketing, and inventory systems.&lt;/p&gt;
&lt;h3 id=&quot;4-lost-update&quot;&gt;4. Lost Update&lt;/h3&gt;
&lt;p&gt;Two transactions read the same value, independently compute an update, and write it back — one silently overwrites the other.&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.6.9&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 898 1021&quot;&gt;&lt;svg class=&quot;d2-2159845675 d2-svg&quot; width=&quot;898&quot; height=&quot;1021&quot; viewBox=&quot;-13 27 898 1021&quot;&gt;&lt;rect x=&quot;-13.000000&quot; y=&quot;27.000000&quot; width=&quot;898.000000&quot; height=&quot;1021.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-2159845675 .text {
	font-family: &quot;d2-2159845675-font-regular&quot;;
}
@font-face {
	font-family: d2-2159845675-font-regular;
	src: url(&quot;data:application/font-woff;base64,d09GRgABAAAAABKEAAoAAAAAG6QAAguFAAAAAAAAAAAAAAAAAAAAAAAAAABPUy8yAAAA9AAAAGAAAABgXd/Vo2NtYXAAAAFUAAAA4gAAATQmyCl4Z2x5ZgAAAjgAAAtYAAAPaPtQ1qpoZWFkAAANkAAAADYAAAA2G4Ue32hoZWEAAA3IAAAAJAAAACQKhAX5aG10eAAADewAAADDAAAA3GjRDGtsb2NhAAAOsAAAAHAAAABwbjhyNG1heHAAAA8gAAAAIAAAACAATwD2bmFtZQAAD0AAAAMjAAAIFAbDVU1wb3N0AAASZAAAAB0AAAAg/9EAMgADAgkBkAAFAAACigJYAAAASwKKAlgAAAFeADIBIwAAAgsFAwMEAwICBGAAAvcAAAADAAAAAAAAAABBREJPAEAAIP//Au7/BgAAA9gBESAAAZ8AAAAAAeYClAAAACAAA3icjM+7LvMBHIfxz/9t32P79j31dahTqw4tVVULQweDiMQgEulsEWKQSCSuwx24ABGsCDciXIKBTX6iCbPv/CTf50EiJUFWOqmgpigtq6ikbFxVXdO8lkXLVq1r27Rt176DYr50GME7XVHXMKdlwZIVa9o2bNmx90bHvYycL77GczzFQzzGTVzHVVzGRZzHWZzGSRzfFW6POl4fX6JmxpRpDZPGOjZVE5o+SUn7/Prpm+9+yMj6KeeX3/7465+8/7p069GroE+/AYOGOmXDykaMqpvlBQAA//8BAAD//7AaM2gAAHicdFd7bFvXef/OIcVrRZQlirx8SKT4ODIv35R4eXlFUSItiqQelkSK1FuWbNmyZVmx58hNMjuK3cKKY8Rexq42EjSO5z6AJNi8ZBtgtzAGFOliKItnY1uRrEPtFv1DCJa1XQQObbrqcriXFCMXyx/EPX/c+53v+73OIVTBFADm8FWQQTXUQQPQAKzKqtpjZRhC8SzPE52MZ5CKmkI/E/II9QfloZC8Lf5Z/Mz582jyHL669XTH2uLiB3PPPy/82canQgA9+BQwyACwCeehGlQAaopl7HaGKBQyNasmDKE+Mn9gbrDUy+ss//F47vFU9Dcx9CcLC/yJcPiEMI3zW6fW1wEAZDANgFtwHlTQCETsjQ1otbRGQdHSQ0FkbCDEBe2EqLYX0z/uORJu80f2xU4NnJsfHRgaOrIyNjc7voLzllRHW7pOXjOc2DvuQmc6AuHWrUIs3hUGAATBYgE34etgAqiy2e1cMBRiA1odZbcTm0JBa7RaNhDidQoFyma/sW9wLde53+htjLuis2xgJuofMPuYQ8qR15ePv55ts4SMtu7nstkzcYct6A0AAJZmCeI87BIxkSahNQrCVPr+/us33rw2tu/06dOn9+H8O9ff/JvE5dXVl6TepgHQY5yHGokf2kqzNKGt9DQ6K/z0iy9QG86nHvT+urcyhx1fB8tXzSGOwRGOVSkUaP/4xcHhSxOJWaPPEA/ED3HPLJG96sufmJfKo7DNocaW7ueyq9+kG/4qKfyX1V3uBwe2+xEVw6qIyqqazqG20VHhIc4Lv0LqrVOIEz7a7h9u4byoC/H96ZxIcnmu+zgPVeU69HQOmXF+6444SnmfF3Fe5IRVsWqtVseGQrxa3C0Y4gklIzKGaLW0anrhnFKnlCtp5eqR4V0yeXCVXw3KZRTOC9+1JW22pA3NbZ1CS55l9zXhr9HoNfeyR3itsocX50Fd2kPH2u2cOM925fFf9cplVHr8171yuVhv4VJgOYhyW6fQmy+3HQsK7wCWMD+Cr0PdH6lHEikTCEkU2yQRocHs+d7e89ncub6+c7nIROvxycnjrZPK0W8vLb02MvLa0tK3R/t7zmTPvvrq2eyZHqhop0bCW7PDBYSovpT93YGT0YtPP31oPDcxPofzLWN9iwvCH1Bfd6qXr9Sw4DzsBt1OJ6mJbGeZf+45Fskk3pq78fzJoWx26CTOk5HE4KxK+CWihc/QVGxvd7DEjatYQL/B18ErTczwkj+4oN3OMD78pOrEuXW6ZiyigeqTz7kD5ADb3WdqM8+Zu5zcXCSyQLzN/T6+xxponLV3tYQWlJynY4830mpzGHc7a13x1kDa620JmaxBj9nZWOOo93a3BccCgMAIgP6A80CJUxHOShPVL++hX9zDA6nU1u1SrxPFAvbhvJhvEjsqVlXyc0haKhSop2c5mnMm3Z6UMxM9rgytLqFvCC+mZ+z2mTS6IJxfWg0BEpHDv8d5sAKwsh16/HIlI7JS1lGy714eT1ZrquU1+pqZwRmlXimvbngqmbm0cLi6bpecatg1j/PCG9xxjlsOoiPCG8Hl0mrrFLps77fb++3CsyVtob9Fm9AILQA6mygtPijBSjESyLSKiBsyoq0lg7/fNfLnb6jcDteAyWI73DGVSVAy24iWRMmZ+YCyvzszpjK3E4smrHWemBE+7jC64jbzy3WdfucewJAtFtD/4nVQlxOEIRRRsTRV2quk55KcxRRGTlu/RUbFs9iadhw4FDmQ6kxHkua9xBJTWk0BvP7+pIm5+EzuuWhycTpz2GYpGnUlTnzFAnoXbYr8fXVOiXHbsPdYZ/dytDVpcNF+kyfJ5HpsHdoWa0bZuZLJrnTadCG13j/Wnls0aXiTVdS6v1hAP92eoYSZVJzh2G2weK6y0e9mTkbmeVfUIs8lKJlx0LC30xxuZmL2lPKlM+nT0ebG3N2t9rDRmewRjDp/rn3iMGCp/39Cm6AH8xMTiKayVg4LmVWCCum6j0djC/zsEYSFH1RNpEikyWROf4TksTA7ouxaSWdWoqvHag3VQ/tpVUjTjOwDQ2kJp2YAFMM/KZ3NhOO5YBknYqPFc0B1MB5P9utc9Q1NxsTiIvpetGpoYKKaiinnhnqEWalGFgB9gtfL6bHNpZiiEo+qbFZGhgJDvVlP657IHrz+/oLVPz8r3EfORNS+R7gJxSIkAeDv8W1sBzEAFMCtQqX2Bl4HZSnDWTVLqQlD0dkR2cOZ7/1w+tUZvC40I/ix8Og/j3+9/E2xAP+O16GuxI5kxzJg7/ic2d3Vcoqq2aVVhjl8dOuqWoVQVC4v7YU/R5uS/1SsaDkRiiemoSrPbIKSWQbd7bE6+7BnX3/W4wslsh5/KIE2UsTf5nEGt0fcJ9wsP7axQptlrMp77MQqQcnIcAUsqdgTWJW18d9oE+qg6f89DyrHAaqLLMZii5HOo7HY0c7Y0FAsOjxc1nXnSjaz0plYzI0eOzaaW9zGeg5tlm8Qpd7Kjik1ZuhzmnT1Sk2duceANiZ9oaf65PJAVFgv4W4sFtAFtAkuCfedmS1F9h8ldimw/yU4R5yWhLu11co22eKuqbR32OgwhCw+d3NrE0l4nWklY+QNVq/ZYNM9VWvlnJG0RRdU611GnYmuqbXyPibukPbXFwsoiU+KOSrxTjieZyURV/j/bLirb/Cp5IULVldts7Je41dO96HaaNWlSz3CpretWh6laqRa+4oF9ABtiDw9oSFV2eK/GOrLuVvtEZuIi21QOT+LgsIniSjjRlNC46CjFRDsBkDvoQ0wALA8w+rKMc6zlI6U76wUtfsvvzXVXaOvlddoayLj37ox1VvbuFteq1fGhU+X1S6NxqVe/vx/ntF6aNqte0Y6az3FAvoAvwI125MGy8mwk/svDp44cfDAiRMH2hOJ9vZkUnnr5nfefvs7N2/Fz1+58sILV66cl+ZMA6A7+JzkLzG+uFCIF02c/ouvebobY2sJ9DG3S1e/dS9R4rgFAP0jfkVUHstFcTmqmUp8i+ZnacfBi6nOLkfC6HfMRKeO9jw72Nhu+GHbwW8+y/Ipr8Xv4RbHOl94OY3lvSADZ7GA1vErYAYPhKWJJEWLGfpl6ikouqQY2c77jqwsMClpf985xxO+mYRas2xu3ujQmAIWdlZlIR2cJ+JMVLUnW9M+O5tWejMBV3dbvdzQF2gbcB4csEb8dfJ6T5fbP+xFx0x7iT/e7rcHiHAv1uYM2hsMKQ+XLN2VHMUC+pGEvQNAXdKEpGl1RfEhXqEgtidM+WwkYuk17+rr8nVPskONPg3f7B30o+aMI3s4OMbGFsLJk+gfov0O7+z80NbvGGNQZwz+6VG75/Chrv3BxKXFr18v31m7iwX4AayId+OdzL9oIMSgJ0RJmkyEmJqI2OtYsQD38Q2oEh3NyxiWklE7vvlaDc7hGmP5y3vo7NyccPFfKwUQZNC78Db+O/H+rGYYlqIO18smZfXo3bf2738LEDjh5/i3SC/eu3nOSjvxg5+Hw1L+ZlA1/hnUAugkCkXn0Rqt7uNoKhVlO8LhjveOPFpbe7ygP/BoZeXRAUBgL2bgUfkbRmJYRJPWKKak99loKvVe+W39wuO1tUeAxf9s6N8kLZpFhxGu9GMp6UcT6Ud4QqlZnkwbMhMNY/t1nO4lPacfEdcGTr9msKw1rN0PX+24c+fOnY6r4fv376OqqwDimWSDH6GH6CfYDiFYBgWE4JrEAVP8HKcxBdUAVQxv5awMj2gUc38oDKDbH7pRfZ3vbuKuT/itvHKGwffRxvb/k2wWbQiNgIof4gHg8W2RS9UOXvRms15vNuMBk0Hf3Kw3mMQaNuRGD9GSWEPNWWkbuoXc0SgA/B8AAAD//wEAAP//m5FWcgABAAAAAguFnbpkK18PPPUAAwPoAAAAANhdoKEAAAAA3WYvNv46/tsIbwPIAAAAAwACAAAAAAAAAAEAAAPY/u8AAAiY/jr+OghvAAEAAAAAAAAAAAAAAAAAAAA3eJwUxzEuBGEYxvH/80yhI1GwxWYz7AaDzDQTiYhCoSIhbyLidQAR5xANvd491OsEbqDlaza2WlH+/MINU3BN5XPSR/S+I71C+p7ez6SWSH2R/iT9RPqV3gekD0mvsesBQz9yXa2yrl96N4SmtN6j0w+tJoxcE8w41TfBgqiOCY8Jj2h1S+iNoYKBa870zrIK+ypcqDBRoVFhhzkn2uCKOZdVTaOOUMeWCmMVNv3ANjMCFh///gMAAP//AQAA///MHSqIAAAAACwALABQAIYAtgDUAOoBHAE0AUABUAGCAaQB1AH2Ah4CYgJ0ApgC0gMKAz4DbAOeA9ID9AQWBCIEPARYBIoErATYBPgFOAVeBYAFrAXSBeoGFAZqBqoGwAbgBvAG/AcWBzAHYAdsB4QHkAemB7QAAQAAADcAjAAMAGYABwABAAAAAAAAAAAAAAAAAAQAA3icnJTdThtXFIU/B9ttVDUXFYrIDTqXbZWM3QiiBK5MCYpVhFOP0x+pqjR4xj9iPDPyDFCqPkCv+xZ9i1z1OfoQVa+rs7wNNqoUgRCwzpy991lnr7UPsMm/bFCrPwT+av5guMZ2c8/wAx41nxre4Ljxt+H6SkyDuPGb4SZfNvqGP+J9/Q/DH7NT/9nwQ7bqR4Y/4Xl90/CnG45/DD9ih/cLXIOX/G64xhaF4Qds8pPhDR5jNWt1HtM23OAztg032QYGTKlImZIxxjFiyphz5iSUhCTMmTIiIcbRpUNKpa8ZkZBj/L9fI0Iq5kSqOKHCkRKSElEysYq/KivnrU4caTW3vQ4VEyJOlXFGRIYjZ0xORsKZ6lRUFOzRokXJUHwLKkoCSqakBOTMGdOixxHHDJgwpcRxpEqeWUjOiIpLIp3vLMJ3ZkhCRmmszsmIxdOJX6LsLsc4ehSKXa18vFbhKY7vlO255Yr9ikC/boXZ+rlLNhEX6meqrqTauZSCE+36czt8K1yxh7tXf9aZfLhHsf5XqnzKufSPpVQmJhnObdEhlINC9wTHgdZdQnXke7oMeEOPdwy07tCnT4cTBnR5rdwefRxf0+OEQ2V0hRd7R3LMCT/i+IauYnztxPqzUCzhFwpzdymOc91jRqGee+aB7prohndX2M9QvuaOUjlDzZGPdNIv05xFjM0VhRjO1MulN0rrX2yOmOkuXtubfT8NFzZ7yym+ItcMe7cuOHnlFow+pGpwyzOX+gmIiMk5VcSQnBktKq7E+y0R56Q4DtW9N5qSis51jj/nSi5JmIlBl0x15hT6G5lvQuM+XPO9s7ckVr5nenZ9q/uc4tSrG43eqXvLvdC6nKwo0DJV8xU3DcU1M+8nmqlV/qFyS71uOc/ok0j1VDe4/Q48J6DNDrvsM9E5Q+1c2BvR1jvR5hX76sEZiaJGcnViFXYJeMEuu7zixVrNDocc0GP/DhwXWT0OeH1rZ12nZRVndf4Um7b4Op5dr17eW6/P7+DLLzRRNy9jX9r4bl9YtRv/nxAx81zc1uqd3BOC/wAAAP//AQAA//8HW0wwAHicYmBmAIP/5xiMGLAAAAAAAP//AQAA//8vAQIDAAAA&quot;);
}
.d2-2159845675 .text-italic {
	font-family: &quot;d2-2159845675-font-italic&quot;;
}
@font-face {
	font-family: d2-2159845675-font-italic;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-2159845675 .fill-N1{fill:#0A0F25;}
		.d2-2159845675 .fill-N2{fill:#676C7E;}
		.d2-2159845675 .fill-N3{fill:#9499AB;}
		.d2-2159845675 .fill-N4{fill:#CFD2DD;}
		.d2-2159845675 .fill-N5{fill:#DEE1EB;}
		.d2-2159845675 .fill-N6{fill:#EEF1F8;}
		.d2-2159845675 .fill-N7{fill:#FFFFFF;}
		.d2-2159845675 .fill-B1{fill:#0D32B2;}
		.d2-2159845675 .fill-B2{fill:#0D32B2;}
		.d2-2159845675 .fill-B3{fill:#E3E9FD;}
		.d2-2159845675 .fill-B4{fill:#E3E9FD;}
		.d2-2159845675 .fill-B5{fill:#EDF0FD;}
		.d2-2159845675 .fill-B6{fill:#F7F8FE;}
		.d2-2159845675 .fill-AA2{fill:#4A6FF3;}
		.d2-2159845675 .fill-AA4{fill:#EDF0FD;}
		.d2-2159845675 .fill-AA5{fill:#F7F8FE;}
		.d2-2159845675 .fill-AB4{fill:#EDF0FD;}
		.d2-2159845675 .fill-AB5{fill:#F7F8FE;}
		.d2-2159845675 .stroke-N1{stroke:#0A0F25;}
		.d2-2159845675 .stroke-N2{stroke:#676C7E;}
		.d2-2159845675 .stroke-N3{stroke:#9499AB;}
		.d2-2159845675 .stroke-N4{stroke:#CFD2DD;}
		.d2-2159845675 .stroke-N5{stroke:#DEE1EB;}
		.d2-2159845675 .stroke-N6{stroke:#EEF1F8;}
		.d2-2159845675 .stroke-N7{stroke:#FFFFFF;}
		.d2-2159845675 .stroke-B1{stroke:#0D32B2;}
		.d2-2159845675 .stroke-B2{stroke:#0D32B2;}
		.d2-2159845675 .stroke-B3{stroke:#E3E9FD;}
		.d2-2159845675 .stroke-B4{stroke:#E3E9FD;}
		.d2-2159845675 .stroke-B5{stroke:#EDF0FD;}
		.d2-2159845675 .stroke-B6{stroke:#F7F8FE;}
		.d2-2159845675 .stroke-AA2{stroke:#4A6FF3;}
		.d2-2159845675 .stroke-AA4{stroke:#EDF0FD;}
		.d2-2159845675 .stroke-AA5{stroke:#F7F8FE;}
		.d2-2159845675 .stroke-AB4{stroke:#EDF0FD;}
		.d2-2159845675 .stroke-AB5{stroke:#F7F8FE;}
		.d2-2159845675 .background-color-N1{background-color:#0A0F25;}
		.d2-2159845675 .background-color-N2{background-color:#676C7E;}
		.d2-2159845675 .background-color-N3{background-color:#9499AB;}
		.d2-2159845675 .background-color-N4{background-color:#CFD2DD;}
		.d2-2159845675 .background-color-N5{background-color:#DEE1EB;}
		.d2-2159845675 .background-color-N6{background-color:#EEF1F8;}
		.d2-2159845675 .background-color-N7{background-color:#FFFFFF;}
		.d2-2159845675 .background-color-B1{background-color:#0D32B2;}
		.d2-2159845675 .background-color-B2{background-color:#0D32B2;}
		.d2-2159845675 .background-color-B3{background-color:#E3E9FD;}
		.d2-2159845675 .background-color-B4{background-color:#E3E9FD;}
		.d2-2159845675 .background-color-B5{background-color:#EDF0FD;}
		.d2-2159845675 .background-color-B6{background-color:#F7F8FE;}
		.d2-2159845675 .background-color-AA2{background-color:#4A6FF3;}
		.d2-2159845675 .background-color-AA4{background-color:#EDF0FD;}
		.d2-2159845675 .background-color-AA5{background-color:#F7F8FE;}
		.d2-2159845675 .background-color-AB4{background-color:#EDF0FD;}
		.d2-2159845675 .background-color-AB5{background-color:#F7F8FE;}
		.d2-2159845675 .color-N1{color:#0A0F25;}
		.d2-2159845675 .color-N2{color:#676C7E;}
		.d2-2159845675 .color-N3{color:#9499AB;}
		.d2-2159845675 .color-N4{color:#CFD2DD;}
		.d2-2159845675 .color-N5{color:#DEE1EB;}
		.d2-2159845675 .color-N6{color:#EEF1F8;}
		.d2-2159845675 .color-N7{color:#FFFFFF;}
		.d2-2159845675 .color-B1{color:#0D32B2;}
		.d2-2159845675 .color-B2{color:#0D32B2;}
		.d2-2159845675 .color-B3{color:#E3E9FD;}
		.d2-2159845675 .color-B4{color:#E3E9FD;}
		.d2-2159845675 .color-B5{color:#EDF0FD;}
		.d2-2159845675 .color-B6{color:#F7F8FE;}
		.d2-2159845675 .color-AA2{color:#4A6FF3;}
		.d2-2159845675 .color-AA4{color:#EDF0FD;}
		.d2-2159845675 .color-AA5{color:#F7F8FE;}
		.d2-2159845675 .color-AB4{color:#EDF0FD;}
		.d2-2159845675 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-2159845675);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-2159845675);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-2159845675);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-2159845675);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-2159845675);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-2159845675);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-2159845675);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-2159845675);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-2159845675);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-2159845675);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-2159845675);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-2159845675);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-2159845675);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-2159845675);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-2159845675);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-2159845675);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-2159845675);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-2159845675);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;QQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;12.000000&quot; y=&quot;52.000000&quot; width=&quot;175.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;99.500000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Txn A (Order #1001)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;REI=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;367.000000&quot; y=&quot;52.000000&quot; width=&quot;107.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;420.500000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Database&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Qg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;684.000000&quot; y=&quot;52.000000&quot; width=&quot;176.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;772.000000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Txn B (Order #1002)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLS0gKVswXQ==&quot;&gt;&lt;path d=&quot;M 99.500000 120.000000 L 99.500000 1022.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-2159845675)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KERCIC0tIClbMF0=&quot;&gt;&lt;path d=&quot;M 420.500000 120.000000 L 420.500000 1022.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-2159845675)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLS0gKVswXQ==&quot;&gt;&lt;path d=&quot;M 772.000000 120.000000 L 772.000000 1022.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-2159845675)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgREIpWzBd&quot;&gt;&lt;marker id=&quot;mk-d2-2159845675-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 101.500000 198.000000 L 416.500000 198.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-2159845675-3488378134)&quot; mask=&quot;url(#d2-2159845675)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;260.500000&quot; y=&quot;204.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;BEGIN&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgREIpWzBd&quot;&gt;&lt;path d=&quot;M 770.000000 288.000000 L 424.500000 288.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-2159845675-3488378134)&quot; mask=&quot;url(#d2-2159845675)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;596.500000&quot; y=&quot;294.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;BEGIN&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgREIpWzFd&quot;&gt;&lt;path d=&quot;M 101.500000 378.000000 L 416.500000 378.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-2159845675-3488378134)&quot; mask=&quot;url(#d2-2159845675)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;260.500000&quot; y=&quot;384.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;SELECT stock WHERE sku=&apos;WIDGET&apos; → 10&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgREIpWzFd&quot;&gt;&lt;path d=&quot;M 770.000000 468.000000 L 424.500000 468.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-2159845675-3488378134)&quot; mask=&quot;url(#d2-2159845675)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;596.500000&quot; y=&quot;474.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;SELECT stock WHERE sku=&apos;WIDGET&apos; → 10&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgREIpWzJd&quot;&gt;&lt;path d=&quot;M 101.500000 558.000000 L 416.500000 558.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-2159845675-3488378134)&quot; mask=&quot;url(#d2-2159845675)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;260.000000&quot; y=&quot;564.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;UPDATE stock = 9&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgREIpWzNd&quot;&gt;&lt;path d=&quot;M 101.500000 648.000000 L 416.500000 648.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-2159845675-3488378134)&quot; mask=&quot;url(#d2-2159845675)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;260.000000&quot; y=&quot;654.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;COMMIT&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgREIpWzJd&quot;&gt;&lt;path d=&quot;M 770.000000 738.000000 L 424.500000 738.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-2159845675-3488378134)&quot; mask=&quot;url(#d2-2159845675)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;596.500000&quot; y=&quot;744.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;UPDATE stock = 9 (based on stale read of 10!)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgREIpWzNd&quot;&gt;&lt;path d=&quot;M 770.000000 828.000000 L 424.500000 828.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-2159845675-3488378134)&quot; mask=&quot;url(#d2-2159845675)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;596.000000&quot; y=&quot;834.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;COMMIT&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KERCIC0mZ3Q7IERCKVswXQ==&quot;&gt;&lt;path d=&quot;M 422.500000 908.000000 L 566.000000 908.000000 S 576.000000 908.000000 576.000000 918.000000 L 576.000000 943.000000 S 576.000000 953.000000 566.000000 953.000000 L 424.500000 953.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-2159845675-3488378134)&quot; mask=&quot;url(#d2-2159845675)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;576.500000&quot; y=&quot;936.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Stock is 9 — should be 8. One decrement lost!&lt;/text&gt;&lt;/g&gt;&lt;mask id=&quot;d2-2159845675&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-13&quot; y=&quot;27&quot; width=&quot;898&quot; height=&quot;1021&quot;&gt;
&lt;rect x=&quot;-13&quot; y=&quot;27&quot; width=&quot;898&quot; height=&quot;1021&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;34.500000&quot; y=&quot;74.500000&quot; width=&quot;130&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;389.500000&quot; y=&quot;74.500000&quot; width=&quot;62&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;706.500000&quot; y=&quot;74.500000&quot; width=&quot;131&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;240.000000&quot; y=&quot;188.000000&quot; width=&quot;41&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;576.000000&quot; y=&quot;278.000000&quot; width=&quot;41&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;130.000000&quot; y=&quot;368.000000&quot; width=&quot;261&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;466.000000&quot; y=&quot;458.000000&quot; width=&quot;261&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;204.000000&quot; y=&quot;548.000000&quot; width=&quot;112&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;232.000000&quot; y=&quot;638.000000&quot; width=&quot;56&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;451.000000&quot; y=&quot;728.000000&quot; width=&quot;291&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;568.000000&quot; y=&quot;818.000000&quot; width=&quot;56&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;431.000000&quot; y=&quot;920.000000&quot; width=&quot;291&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;Two orders shipped, stock only dropped by 1. At scale this leads to overselling — shipping products that don’t exist. The safe fix is an atomic update: &lt;code&gt;SET stock = stock - 1&lt;/code&gt; instead of a read-modify-write cycle.&lt;/p&gt;
&lt;h3 id=&quot;5-write-skew&quot;&gt;5. Write Skew&lt;/h3&gt;
&lt;p&gt;Two transactions read the same rows, see a consistent snapshot, and each updates &lt;em&gt;different&lt;/em&gt; rows — but the combined result violates a constraint that no single transaction would have broken on its own.&lt;/p&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.6.9&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 1138 1251&quot;&gt;&lt;svg class=&quot;d2-1575667919 d2-svg&quot; width=&quot;1138&quot; height=&quot;1251&quot; viewBox=&quot;-13 27 1138 1251&quot;&gt;&lt;rect x=&quot;-13.000000&quot; y=&quot;27.000000&quot; width=&quot;1138.000000&quot; height=&quot;1251.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-1575667919 .text {
	font-family: &quot;d2-1575667919-font-regular&quot;;
}
@font-face {
	font-family: d2-1575667919-font-regular;
	src: url(&quot;data:application/font-woff;base64,d09GRgABAAAAABGIAAoAAAAAGkQAAguFAAAAAAAAAAAAAAAAAAAAAAAAAABPUy8yAAAA9AAAAGAAAABgXd/Vo2NtYXAAAAFUAAAA2wAAASgprSYRZ2x5ZgAAAjAAAApsAAAOINAt65FoZWFkAAAMnAAAADYAAAA2G4Ue32hoZWEAAAzUAAAAJAAAACQKhAX3aG10eAAADPgAAADAAAAA1GW7C5Rsb2NhAAANuAAAAGwAAABsZChngm1heHAAAA4kAAAAIAAAACAATQD2bmFtZQAADkQAAAMjAAAIFAbDVU1wb3N0AAARaAAAAB0AAAAg/9EAMgADAgkBkAAFAAACigJYAAAASwKKAlgAAAFeADIBIwAAAgsFAwMEAwICBGAAAvcAAAADAAAAAAAAAABBREJPAEAAIP//Au7/BgAAA9gBESAAAZ8AAAAAAeYClAAAACAAA3icjM67LusBHMDxz/+0PZeengtKXYp/3VpV191gEJEYRCISi1iExCAG8RxewCMgTILwAF5BeAaJTX6Spnbf+TN8kchIUJBNyqhLZeWlquoa5sxbtGzVug2btuzYc+DIcVqsnETQtLWWXbBkxVrLbtu17/DTxouMXLzHW7zGQ9zHXdzGTVzHY1zFZVzEeZw9l55Om0dfLVE3acq0cTUzvsnIyvnuh59+yfut4I+//vmvTbsORQ2dupR069GrT1m/AYNSFUOGjRg1pmrCLB8AAAD//wEAAP//jFY04wB4nHRWa2wbdbY//79dT9M4TRx7PHZqx56Z1ONH7CQejyeO03HjVx5N4sRO0iZpUtKmTdOU3jYVrcoNrbgtbUV1uUZQgaBwEbe6LLuwZRepu6hfVuzSDQsUrYRgWdGC+BBV4rWNsmJZyHg1Yyek1fLJI2vmnPN7nAesg2EALOAnQQNlUAnVQALwBtqwmeY4lhB5UWQpjcghAzGMPpHzCHWGtOGwtin+RfzEqVNox0n85PLBljNTU2+NHz8u//fCbTmIbtwGDBoAbMd5KAMDgJHgOZeLY3U6jZE3shxLvON4y1HtrNJWOv96a/zWsPRNDP3H5KR4fyRyvzyC88uH5+cBADQwAoDrcB4MUAOsUhsfNJtJk44g1R8dq+GDYSHkYlnDysPI7xN7I00N0W2xw10nJwa6enr2zg6Ojw3N4rwz3dKUqdSW9ya3DnnRiZZgpHF5KRbfEgEABKHCEt6EL4EdYB3jcgmhcJgPminC5WIZnY40mc18MCxSOh3KZh/e1n0m17rT5q+Je6UxPjgqNXQ5Atxuff/TMweezjY5wzam7Vg2eyLuZkL+IABgFUsI52G9womKhDTpWG617stPP//cxcFtR48ePboN51++9Nwvkxfm5h5RaxsBQLdwHspVfUia5EmWpMkR9KD88XffoSacT99o/7p9FYcLXwLnT+FQYAiswBt0OrRz6Gx37/ntyTFbwBoPxncLR6bZrcYLHzmmS1D42nBNXdux7NzjZPUvUvKXtK9UDw6u1KM4hjewBtowkkNNAwPy+zgvf4WMy4eRIL+zUj+8ivOKL5T3R3KKyCVc7+I8rCvFIUdyyIHzy79RoJTyPITziia8gTeazRQfDotGJVsoLLKEhtVwrNlMGkYmT+opvVZP6uf29q7XaENz4lxIqyFwXn6RSTFMikHjy4fRdP2M76L8Chq46Jupl59azeHHeTAWc1C8yyUoeFYiD33VrtUQmaGv27VaJd7k+eBMCOWWD6PnzjXtD8kvA1Y534svQeU97lFNygXDqsSMaiLUnT3V3n4qmzvZ0XEyF93eeGDHjgONO/QDz0xPP9Xf/9T09DMDnYkT2Qcfe+zB7IkErHqnXOXbtKYLWNbwo+2vdR2Szh48uHsot31oHOfrBjumJuUfUEdbul1cjeHEedgI1NpOMrKatWHeS+yP9iVfGn/++KGebLbnEM6z/cnuMYP8OSLlL9BwbGtbqKiNt7CEvsGXwK8i5kS1P4SQy8VxAXy36xTcFFWLFTZQVeqYL8ju4ts67E2OcccWjzAejU6y/trOgJiggzVjri114Um9UN+y2R9tZNy2jZ4Kb7wxmPH768J2OlTv8NSUu6v8bU2hwSAgsAGgH3AeCAUVK9Aka/j8OvrsOu5Kp5evFmvdXljCAZxX5puqjoE3FPs5rD7qdCiRmJFynpSvPu3pkw7ow3PT6GH5ocyoyzWaQaflU9NzYUAKc/ifOA80AK9Z48cfnzSspjjrCM2LF4ZSZaYybbmlfLR7VG/Ra8uqN6T6zk/uKatcryWq10/gvPyscEAQZkJor/xsaKb4tHwYXXB1ulydLvkBQAq/6I46S4EXEC3QJKJJPxqWr6MX5f9HY0FsSTct326Hog/Rr9Ai1EAdAMUoNhRDqgQEpwpCGlilOE4ZAeoweHNL//88a/C5vV12J7OnZbgvSWiYfjMrsScmgvrOtr5Bg6OZdZoiZs/9o/KHLTZvnHGcq2xt8GwGDNnCEvoez4OxNG04lmANPEkUcxW9X7S+MrGRh+l0aoh4FtMZ967d0V3p1kw05djKOmN62h7E82/usHNnj+SOSampkb49jLNgo4r6BQpL6ApaVLT+6ZmmjObqrftb22akxpTVSzbY61NcLsG0mOvoPn3rbF92tpWhwkZLw2BzbspuEu20wllDYQl9vIKhyJkanBP4FbJEYTXRP0YPRSdEr+TU5pKExtZt3drqiNRyMVda/8iJzFGptiZ3bbk5YvOkErKNasg1b98DWK3/T2gRLOC4C4HSgPTqYtHQKlWIajsgxSbFsb0Iy79dtz3NRjfZHZl3kDYW4fv1W2YzfbPS3P4Ka1nPTtIQNtUiV1dPRuWpFgDF8AfFPc4KohAq8cQypLIzDPfF46lOyltVvcmWnJpC/yet6+naXkbE9OM9CXlMjZEFQB/h+dKkWdFSmbiqjoZsVsP2BHvas/WNm6Ob8fybk3TDxJj8LvIkJddm+QUoFCAFAK/jq9gFyu7TAT9X1DFbWIK/4HmoLDKttmEJ/MsBT3ZjmZYgyteb9REB71t+0mhASNJqizXhO2hR7TsDr7SaAuuuyojV32yS0Di7fc2xSldv/bbObH0gnMzWN4STaCHNNjTVe0Ir5W6TXyj9rOBGiyXcpRxrcScJDdu7ClwNdhfuks5/Q4tQCZv+7R5YXQOoMjoVi01FW/fFYvtaYz09Mam3t+TR1tls32xrcio3sH//QG4K1D7j0fdoseTRH6tTTiDGxVGkcW2fKZXSGd/47uiuZibB4ONqm8XqaOk9/HqzzX3uSPaYVFszeBnp7ukzhYNxtFi6UIpZSl1WJMDa4bFTVXpTpSNhRQs7AuENHVptUJLni9/bCkvoNFoEr6rv2p2groR7NkJxIfw5NM56nElfYyPNb2Li3uGMv9fmtoadAV9t4yY26fdk9JxNtNJ+h5WhNlTQgieacVIho8Vro+xkeQUtBri4W81vKSyhFD6kzGnVX6wgirxq/FWffdG7paN7Q+r0adpbUauvMjXoRzpQhbTu/PmEvOhvKtNKRLkaa1thCd1AC4of7vKqoTQWPuvpyPkaXVFG4YXp1k+MoZD8UVLifGhYrul2NwICPQD6I1qAinv2hebalcGd5VS5tpzasLP/FbQgf1nXwbIddcgk1wCCjQDoNbQAVgBe5Hiq9KHIExRbuqUJYuP/PjHcVm6p0Jaby6NDTzw/3F5Rs1FbYdHH5dszRq/J5DXO3Pn7EXM9SfqoIyqmOgD0B/yo4k5ekHDJMtyqmZRm50n3fWfTrVvcSVuDe1Qa3pd4oLum2fpG032PP8CLab+zoV6YGmz9z3MZrG0HBA2FIbgOs1ANQHHhMKdjWHWIFkMmTL5GhHXYwtZZnZvTP280xtzIbtvkCPm3Tqg19aEr8DP8a+UGNHIcTxB7qjQ7NFXoyks7d74ECDzwKf4WWZTbURRo0oNvfBqJKNwW/gvdLryh/E8JNKlHn5wURXXG9KEy/InCOaU2oKI6aTJTH0rptMS3RCItr+29eebMrUnLrpuzszd3AQJXoQ9ulr7h1GtN8S5p0g2r7/NSOv1a6W3L5K0zZ24CghZ0Ge3H84pWRk7kRErkKZEiKIJ71B2ZqNxX1lQ2VTnRzLWjy/Zxd8B6cMYScI/bh5T5yMDv0PvoA+yCEMyADkJwUeWCK9zBGUwou34dJ9ICzYmIRDHf23IXuvq2D1VVBq4lrwXkb7Wr/QqX0cLKXZ3NogXFP4W3cReI+KpynxvWiGFxOCwWhwN32a2W2lqL1a7EYJAPvY+mlRhGgSYZ9CrySRIA/AsAAP//AQAA//+GfgpaAAEAAAACC4UIhmMlXw889QADA+gAAAAA2F2goQAAAADdZi82/jr+2whvA8gAAAADAAIAAAAAAAAAAQAAA9j+7wAACJj+Ov46CG8AAQAAAAAAAAAAAAAAAAAAADV4nBzKsS6DYRiG4ft5/sHSkBhoomn+0JAS/ZYvEsRoYpB3Ea8DEHEcYmE3cx7mmg3OwKyJNDpVdLySy09cMQa3ND4nfUz1DekV0rdUP5JaIvVF+pP0A+lnqg9IH5JeY9dder7nslll3Rvs65fqIaExI+9R9M1IA/puCaacMieaE8JbhPuLE7om9EpPQdctZ/qgozeWNWHAjMKMi6ZlqB86KoQK23rhSBM2fccOUwLm7//+AwAA//8BAAD//9DGJpsAAAAsACwAUACGALYA1ADqARwBNAFAAVABggGkAdQB9gIeAmICdAKYAtIC6AMgA1QDggO0A+gECgQsBDgEVASGBKgE1AUIBSgFaAWOBbAFzAX4BiIGQgZSBl4GagaEBp4GvAbIBuAG7AcCBxAAAQAAADUAjAAMAGYABwABAAAAAAAAAAAAAAAAAAQAA3icnJTdThtXFIU/B9ttVDUXFYrIDTqXbZWM3QiiBK5MCYpVhFOP0x+pqjR4xj9iPDPyDFCqPkCv+xZ9i1z1OfoQVa+rs7wNNqoUgRCwzpy991lnr7UPsMm/bFCrPwT+av5guMZ2c8/wAx41nxre4Ljxt+H6SkyDuPGb4SZfNvqGP+J9/Q/DH7NT/9nwQ7bqR4Y/4Xl90/CnG45/DD9ih/cLXIOX/G64xhaF4Qds8pPhDR5jNWt1HtM23OAztg032QYGTKlImZIxxjFiyphz5iSUhCTMmTIiIcbRpUNKpa8ZkZBj/L9fI0Iq5kSqOKHCkRKSElEysYq/KivnrU4caTW3vQ4VEyJOlXFGRIYjZ0xORsKZ6lRUFOzRokXJUHwLKkoCSqakBOTMGdOixxHHDJgwpcRxpEqeWUjOiIpLIp3vLMJ3ZkhCRmmszsmIxdOJX6LsLsc4ehSKXa18vFbhKY7vlO255Yr9ikC/boXZ+rlLNhEX6meqrqTauZSCE+36czt8K1yxh7tXf9aZfLhHsf5XqnzKufSPpVQmJhnObdEhlINC9wTHgdZdQnXke7oMeEOPdwy07tCnT4cTBnR5rdwefRxf0+OEQ2V0hRd7R3LMCT/i+IauYnztxPqzUCzhFwpzdymOc91jRqGee+aB7prohndX2M9QvuaOUjlDzZGPdNIv05xFjM0VhRjO1MulN0rrX2yOmOkuXtubfT8NFzZ7yym+ItcMe7cuOHnlFow+pGpwyzOX+gmIiMk5VcSQnBktKq7E+y0R56Q4DtW9N5qSis51jj/nSi5JmIlBl0x15hT6G5lvQuM+XPO9s7ckVr5nenZ9q/uc4tSrG43eqXvLvdC6nKwo0DJV8xU3DcU1M+8nmqlV/qFyS71uOc/ok0j1VDe4/Q48J6DNDrvsM9E5Q+1c2BvR1jvR5hX76sEZiaJGcnViFXYJeMEuu7zixVrNDocc0GP/DhwXWT0OeH1rZ12nZRVndf4Um7b4Op5dr17eW6/P7+DLLzRRNy9jX9r4bl9YtRv/nxAx81zc1uqd3BOC/wAAAP//AQAA//8HW0wwAHicYmBmAIP/5xiMGLAAAAAAAP//AQAA//8vAQIDAAAA&quot;);
}
.d2-1575667919 .text-italic {
	font-family: &quot;d2-1575667919-font-italic&quot;;
}
@font-face {
	font-family: d2-1575667919-font-italic;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-1575667919 .fill-N1{fill:#0A0F25;}
		.d2-1575667919 .fill-N2{fill:#676C7E;}
		.d2-1575667919 .fill-N3{fill:#9499AB;}
		.d2-1575667919 .fill-N4{fill:#CFD2DD;}
		.d2-1575667919 .fill-N5{fill:#DEE1EB;}
		.d2-1575667919 .fill-N6{fill:#EEF1F8;}
		.d2-1575667919 .fill-N7{fill:#FFFFFF;}
		.d2-1575667919 .fill-B1{fill:#0D32B2;}
		.d2-1575667919 .fill-B2{fill:#0D32B2;}
		.d2-1575667919 .fill-B3{fill:#E3E9FD;}
		.d2-1575667919 .fill-B4{fill:#E3E9FD;}
		.d2-1575667919 .fill-B5{fill:#EDF0FD;}
		.d2-1575667919 .fill-B6{fill:#F7F8FE;}
		.d2-1575667919 .fill-AA2{fill:#4A6FF3;}
		.d2-1575667919 .fill-AA4{fill:#EDF0FD;}
		.d2-1575667919 .fill-AA5{fill:#F7F8FE;}
		.d2-1575667919 .fill-AB4{fill:#EDF0FD;}
		.d2-1575667919 .fill-AB5{fill:#F7F8FE;}
		.d2-1575667919 .stroke-N1{stroke:#0A0F25;}
		.d2-1575667919 .stroke-N2{stroke:#676C7E;}
		.d2-1575667919 .stroke-N3{stroke:#9499AB;}
		.d2-1575667919 .stroke-N4{stroke:#CFD2DD;}
		.d2-1575667919 .stroke-N5{stroke:#DEE1EB;}
		.d2-1575667919 .stroke-N6{stroke:#EEF1F8;}
		.d2-1575667919 .stroke-N7{stroke:#FFFFFF;}
		.d2-1575667919 .stroke-B1{stroke:#0D32B2;}
		.d2-1575667919 .stroke-B2{stroke:#0D32B2;}
		.d2-1575667919 .stroke-B3{stroke:#E3E9FD;}
		.d2-1575667919 .stroke-B4{stroke:#E3E9FD;}
		.d2-1575667919 .stroke-B5{stroke:#EDF0FD;}
		.d2-1575667919 .stroke-B6{stroke:#F7F8FE;}
		.d2-1575667919 .stroke-AA2{stroke:#4A6FF3;}
		.d2-1575667919 .stroke-AA4{stroke:#EDF0FD;}
		.d2-1575667919 .stroke-AA5{stroke:#F7F8FE;}
		.d2-1575667919 .stroke-AB4{stroke:#EDF0FD;}
		.d2-1575667919 .stroke-AB5{stroke:#F7F8FE;}
		.d2-1575667919 .background-color-N1{background-color:#0A0F25;}
		.d2-1575667919 .background-color-N2{background-color:#676C7E;}
		.d2-1575667919 .background-color-N3{background-color:#9499AB;}
		.d2-1575667919 .background-color-N4{background-color:#CFD2DD;}
		.d2-1575667919 .background-color-N5{background-color:#DEE1EB;}
		.d2-1575667919 .background-color-N6{background-color:#EEF1F8;}
		.d2-1575667919 .background-color-N7{background-color:#FFFFFF;}
		.d2-1575667919 .background-color-B1{background-color:#0D32B2;}
		.d2-1575667919 .background-color-B2{background-color:#0D32B2;}
		.d2-1575667919 .background-color-B3{background-color:#E3E9FD;}
		.d2-1575667919 .background-color-B4{background-color:#E3E9FD;}
		.d2-1575667919 .background-color-B5{background-color:#EDF0FD;}
		.d2-1575667919 .background-color-B6{background-color:#F7F8FE;}
		.d2-1575667919 .background-color-AA2{background-color:#4A6FF3;}
		.d2-1575667919 .background-color-AA4{background-color:#EDF0FD;}
		.d2-1575667919 .background-color-AA5{background-color:#F7F8FE;}
		.d2-1575667919 .background-color-AB4{background-color:#EDF0FD;}
		.d2-1575667919 .background-color-AB5{background-color:#F7F8FE;}
		.d2-1575667919 .color-N1{color:#0A0F25;}
		.d2-1575667919 .color-N2{color:#676C7E;}
		.d2-1575667919 .color-N3{color:#9499AB;}
		.d2-1575667919 .color-N4{color:#CFD2DD;}
		.d2-1575667919 .color-N5{color:#DEE1EB;}
		.d2-1575667919 .color-N6{color:#EEF1F8;}
		.d2-1575667919 .color-N7{color:#FFFFFF;}
		.d2-1575667919 .color-B1{color:#0D32B2;}
		.d2-1575667919 .color-B2{color:#0D32B2;}
		.d2-1575667919 .color-B3{color:#E3E9FD;}
		.d2-1575667919 .color-B4{color:#E3E9FD;}
		.d2-1575667919 .color-B5{color:#EDF0FD;}
		.d2-1575667919 .color-B6{color:#F7F8FE;}
		.d2-1575667919 .color-AA2{color:#4A6FF3;}
		.d2-1575667919 .color-AA4{color:#EDF0FD;}
		.d2-1575667919 .color-AA5{color:#F7F8FE;}
		.d2-1575667919 .color-AB4{color:#EDF0FD;}
		.d2-1575667919 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-1575667919);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-1575667919);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-1575667919);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-1575667919);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-1575667919);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-1575667919);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-1575667919);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-1575667919);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-1575667919);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-1575667919);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-1575667919);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-1575667919);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-1575667919);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-1575667919);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-1575667919);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-1575667919);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-1575667919);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-1575667919);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;QQ==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;12.000000&quot; y=&quot;52.000000&quot; width=&quot;126.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;75.000000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Txn A (Alice)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;REI=&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;441.000000&quot; y=&quot;52.000000&quot; width=&quot;107.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;494.500000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Database&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;Qg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;847.000000&quot; y=&quot;52.000000&quot; width=&quot;122.000000&quot; height=&quot;66.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#EDF0FD&quot; class=&quot;stroke-B1 fill-B5&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;908.000000&quot; y=&quot;90.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Txn B (Bob)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLS0gKVswXQ==&quot;&gt;&lt;path d=&quot;M 75.000000 120.000000 L 75.000000 1252.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-1575667919)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KERCIC0tIClbMF0=&quot;&gt;&lt;path d=&quot;M 494.500000 120.000000 L 494.500000 1252.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-1575667919)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLS0gKVswXQ==&quot;&gt;&lt;path d=&quot;M 908.000000 120.000000 L 908.000000 1252.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B2&quot; style=&quot;stroke-width:2;stroke-dasharray:12.000000,11.838767;&quot; mask=&quot;url(#d2-1575667919)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgREIpWzBd&quot;&gt;&lt;marker id=&quot;mk-d2-1575667919-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 77.000000 198.000000 L 490.500000 198.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1575667919-3488378134)&quot; mask=&quot;url(#d2-1575667919)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;284.500000&quot; y=&quot;204.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;BEGIN (snapshot)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgREIpWzBd&quot;&gt;&lt;path d=&quot;M 906.000000 288.000000 L 498.500000 288.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1575667919-3488378134)&quot; mask=&quot;url(#d2-1575667919)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;701.500000&quot; y=&quot;294.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;BEGIN (snapshot)&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgREIpWzFd&quot;&gt;&lt;path d=&quot;M 77.000000 378.000000 L 490.500000 378.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1575667919-3488378134)&quot; mask=&quot;url(#d2-1575667919)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;285.000000&quot; y=&quot;384.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;SELECT count(*) WHERE on_call=true → 2&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgREIpWzFd&quot;&gt;&lt;path d=&quot;M 906.000000 468.000000 L 498.500000 468.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1575667919-3488378134)&quot; mask=&quot;url(#d2-1575667919)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;701.000000&quot; y=&quot;474.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;SELECT count(*) WHERE on_call=true → 2&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgQSlbMF0=&quot;&gt;&lt;path d=&quot;M 77.000000 548.000000 L 166.500000 548.000000 S 176.500000 548.000000 176.500000 558.000000 L 176.500000 583.000000 S 176.500000 593.000000 166.500000 593.000000 L 79.000000 593.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1575667919-3488378134)&quot; mask=&quot;url(#d2-1575667919)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;176.500000&quot; y=&quot;576.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Sees 2 doctors, safe to leave&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgQilbMF0=&quot;&gt;&lt;path d=&quot;M 910.000000 663.000000 L 999.500000 663.000000 S 1009.500000 663.000000 1009.500000 673.000000 L 1009.500000 698.000000 S 1009.500000 708.000000 999.500000 708.000000 L 912.000000 708.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1575667919-3488378134)&quot; mask=&quot;url(#d2-1575667919)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;1009.500000&quot; y=&quot;691.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Sees 2 doctors, safe to leave&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgREIpWzJd&quot;&gt;&lt;path d=&quot;M 77.000000 788.000000 L 490.500000 788.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1575667919-3488378134)&quot; mask=&quot;url(#d2-1575667919)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;284.500000&quot; y=&quot;794.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;UPDATE doctors SET on_call=false WHERE name=&apos;Alice&apos;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgREIpWzJd&quot;&gt;&lt;path d=&quot;M 906.000000 878.000000 L 498.500000 878.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1575667919-3488378134)&quot; mask=&quot;url(#d2-1575667919)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;701.000000&quot; y=&quot;884.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;UPDATE doctors SET on_call=false WHERE name=&apos;Bob&apos;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEEgLSZndDsgREIpWzNd&quot;&gt;&lt;path d=&quot;M 77.000000 968.000000 L 490.500000 968.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1575667919-3488378134)&quot; mask=&quot;url(#d2-1575667919)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;285.000000&quot; y=&quot;974.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;COMMIT&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEIgLSZndDsgREIpWzNd&quot;&gt;&lt;path d=&quot;M 906.000000 1058.000000 L 498.500000 1058.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1575667919-3488378134)&quot; mask=&quot;url(#d2-1575667919)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;701.000000&quot; y=&quot;1064.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;COMMIT&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KERCIC0mZ3Q7IERCKVswXQ==&quot;&gt;&lt;path d=&quot;M 496.500000 1138.000000 L 626.000000 1138.000000 S 636.000000 1138.000000 636.000000 1148.000000 L 636.000000 1173.000000 S 636.000000 1183.000000 626.000000 1183.000000 L 498.500000 1183.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-1575667919-3488378134)&quot; mask=&quot;url(#d2-1575667919)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;636.500000&quot; y=&quot;1166.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;Zero doctors on call — invariant violated&lt;/text&gt;&lt;/g&gt;&lt;mask id=&quot;d2-1575667919&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-13&quot; y=&quot;27&quot; width=&quot;1138&quot; height=&quot;1251&quot;&gt;
&lt;rect x=&quot;-13&quot; y=&quot;27&quot; width=&quot;1138&quot; height=&quot;1251&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;34.500000&quot; y=&quot;74.500000&quot; width=&quot;81&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;463.500000&quot; y=&quot;74.500000&quot; width=&quot;62&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;869.500000&quot; y=&quot;74.500000&quot; width=&quot;77&quot; height=&quot;21&quot; fill=&quot;rgba(0,0,0,0.75)&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;228.000000&quot; y=&quot;188.000000&quot; width=&quot;113&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;645.000000&quot; y=&quot;278.000000&quot; width=&quot;113&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;152.000000&quot; y=&quot;368.000000&quot; width=&quot;266&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;568.000000&quot; y=&quot;458.000000&quot; width=&quot;266&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;85.000000&quot; y=&quot;560.000000&quot; width=&quot;183&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;918.000000&quot; y=&quot;675.000000&quot; width=&quot;183&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;105.000000&quot; y=&quot;778.000000&quot; width=&quot;359&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;524.000000&quot; y=&quot;868.000000&quot; width=&quot;354&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;257.000000&quot; y=&quot;958.000000&quot; width=&quot;56&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;673.000000&quot; y=&quot;1048.000000&quot; width=&quot;56&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;505.000000&quot; y=&quot;1150.000000&quot; width=&quot;263&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;Neither transaction modified a row the other read, so standard MVCC snapshot rules don’t see a conflict. Snapshot isolation (Postgres Repeatable Read) does &lt;em&gt;not&lt;/em&gt; prevent this. Only true &lt;code&gt;SERIALIZABLE&lt;/code&gt; does.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-four-isolation-levels&quot;&gt;The Four Isolation Levels&lt;/h2&gt;
&lt;p&gt;The SQL standard defines four levels. Each prevents a progressively stricter set of phenomena.&lt;/p&gt;
&lt;h3 id=&quot;read-uncommitted&quot;&gt;Read Uncommitted&lt;/h3&gt;
&lt;p&gt;The weakest level. Transactions can read uncommitted data from others.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prevents:&lt;/strong&gt; nothing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Allows:&lt;/strong&gt; all five phenomena&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When to use:&lt;/strong&gt; almost never. Possibly rough approximate analytics where slightly dirty counts are acceptable and you need maximum read throughput.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When to avoid:&lt;/strong&gt; any transactional system. Any read where the answer drives a decision. Anywhere correctness matters.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Postgres note:&lt;/strong&gt; Postgres internally treats &lt;code&gt;READ UNCOMMITTED&lt;/code&gt; as &lt;code&gt;READ COMMITTED&lt;/code&gt; — it never returns dirty reads even when you ask for them.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;read-committed&quot;&gt;Read Committed&lt;/h3&gt;
&lt;p&gt;Transactions only see committed data. Each statement gets a fresh view of the latest committed state, so the same query inside one transaction may return different rows if run twice.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prevents:&lt;/strong&gt; dirty reads&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Allows:&lt;/strong&gt; non-repeatable reads, phantom reads, lost updates, write skew&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When to use:&lt;/strong&gt; the safe baseline for most OLTP applications — dashboards, user profile reads, standard CRUD. Default in Postgres, Oracle, SQL Server.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When to avoid:&lt;/strong&gt; multi-step logic that reads the same row twice (you’ll see shifting values mid-transaction). Operations that compute derived results from multiple rows that need to be a consistent set.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;repeatable-read&quot;&gt;Repeatable Read&lt;/h3&gt;
&lt;p&gt;Once a transaction reads a row, the transaction continues to see the snapshot from when it began — even if other transactions commit changes to that row in the meantime.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prevents:&lt;/strong&gt; dirty reads, non-repeatable reads&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Allows:&lt;/strong&gt; phantom reads (in standard implementations), write skew&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When to use:&lt;/strong&gt; multi-step business logic that reads the same data multiple times and needs a consistent view. Generating invoices, calculating totals, multi-query reports.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When to avoid:&lt;/strong&gt; anywhere write skew matters (on-call rotations, multi-row constraint enforcement). Use &lt;code&gt;SERIALIZABLE&lt;/code&gt; instead.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Postgres note:&lt;/strong&gt; Repeatable Read in Postgres also prevents lost updates by aborting the second transaction with a &lt;code&gt;40001&lt;/code&gt; serialization error. MySQL’s InnoDB doesn’t — use &lt;code&gt;SELECT … FOR UPDATE&lt;/code&gt; or atomic updates if you’re on MySQL.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MySQL note:&lt;/strong&gt; MySQL InnoDB’s Repeatable Read prevents phantom reads via gap locks on locking reads (&lt;code&gt;SELECT … FOR UPDATE&lt;/code&gt;). Plain &lt;code&gt;SELECT&lt;/code&gt; uses snapshot reads, which can still observe phantoms in some edge cases.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;serializable&quot;&gt;Serializable&lt;/h3&gt;
&lt;p&gt;The strictest level. Transactions execute as if they ran one at a time, sequentially. No concurrency anomalies are possible.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prevents:&lt;/strong&gt; all five phenomena&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Allows:&lt;/strong&gt; nothing — at the cost of more transaction aborts under contention&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When to use:&lt;/strong&gt; financial ledgers, inventory reservation, double-entry bookkeeping, regulatory compliance — anywhere a bug means lost money, corrupted data, or violated invariants. Use it precisely where you need it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When to avoid:&lt;/strong&gt; as a blanket “be safe” setting. The retry cost on contention is real, and most application code doesn’t handle serialization-failure errors correctly. Use Read Committed by default and raise to &lt;code&gt;SERIALIZABLE&lt;/code&gt; only on the transactions that genuinely need it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Postgres note:&lt;/strong&gt; Implemented via SSI (Serializable Snapshot Isolation) — see below.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;the-phenomena-by-level-matrix&quot;&gt;The phenomena-by-level matrix&lt;/h3&gt;













































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Isolation Level&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;Dirty Read&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;Non-Repeatable&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;Phantom&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;Lost Update&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;Write Skew&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Read Uncommitted&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;Possible&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;Possible&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;Possible&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;Possible&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;Possible&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Read Committed&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;Prevented&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;Possible&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;Possible&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;Possible&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;Possible&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Repeatable Read&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;Prevented&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;Prevented&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;Possible *&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;Prevented (PG) †&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;Possible&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Serializable&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;Prevented&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;Prevented&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;Prevented&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;Prevented&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;Prevented&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;* MySQL InnoDB’s Repeatable Read also prevents phantom reads via gap locks.
† PostgreSQL’s Repeatable Read prevents lost updates by aborting the conflicting transaction. MySQL InnoDB’s does not.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;how-postgres-implements-isolation&quot;&gt;How Postgres Implements Isolation&lt;/h2&gt;
&lt;p&gt;Two mechanisms, layered.&lt;/p&gt;
&lt;h3 id=&quot;mvcc--readers-and-writers-dont-block-each-other&quot;&gt;MVCC — readers and writers don’t block each other&lt;/h3&gt;
&lt;p&gt;Every &lt;code&gt;UPDATE&lt;/code&gt; writes a new row version; the old version stays until vacuum reclaims it. Each transaction’s snapshot determines which version it sees. Consequences:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Readers never block writers and vice versa. A long-running &lt;code&gt;SELECT&lt;/code&gt; doesn’t lock anyone out of writing.&lt;/li&gt;
&lt;li&gt;Repeatable Read is implemented by simply pinning the snapshot for the entire transaction.&lt;/li&gt;
&lt;li&gt;The cost is &lt;strong&gt;bloat&lt;/strong&gt; — dead row versions accumulate, and autovacuum reclaims them in the background.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;ssi--serializable-without-predicate-locking&quot;&gt;SSI — Serializable without predicate locking&lt;/h3&gt;
&lt;p&gt;Classical serializable isolation requires predicate locks: locks not on rows, but on query conditions. They’re correct but block aggressively. Postgres instead uses &lt;strong&gt;Serializable Snapshot Isolation (SSI)&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Each transaction runs at Repeatable Read (its own snapshot).&lt;/li&gt;
&lt;li&gt;Postgres tracks read-write dependencies between concurrent transactions in the background.&lt;/li&gt;
&lt;li&gt;At commit time, if Postgres detects a dependency cycle that would produce a non-serializable schedule, it aborts the offending transaction with a serialization-failure error.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The trade: less blocking, more aborts. Your application &lt;strong&gt;must&lt;/strong&gt; be prepared to retry transactions that fail with &lt;code&gt;SQLSTATE 40001&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- In application code:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;BEGIN&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; ISOLATION&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; LEVEL&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; SERIALIZABLE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- ... do work ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;COMMIT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- If COMMIT returns serialization_failure, sleep briefly and retry&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- the whole transaction from BEGIN.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This retry loop is non-negotiable for &lt;code&gt;SERIALIZABLE&lt;/code&gt;. Skipping it means random transaction failures under load.&lt;/p&gt;
&lt;h3 id=&quot;a-note-on-other-databases&quot;&gt;A note on other databases&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Oracle’s “Serializable” is actually snapshot isolation — it permits write skew, despite the name.&lt;/li&gt;
&lt;li&gt;SQL Server has “Serializable” (predicate locking) and “Snapshot” (MVCC) as distinct levels.&lt;/li&gt;
&lt;li&gt;MySQL InnoDB’s Repeatable Read is unusual: it prevents phantoms with gap locks but not lost updates with snapshot conflict detection.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Treat “Serializable” with skepticism across systems — read your DB’s actual semantics.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;concurrency-tools-in-application-code&quot;&gt;Concurrency Tools in Application Code&lt;/h2&gt;
&lt;p&gt;Isolation levels handle concurrency at the database level. In application code, three more tools cover the cases isolation alone won’t fix.&lt;/p&gt;
&lt;h3 id=&quot;select--for-update-pessimistic-locking&quot;&gt;&lt;code&gt;SELECT … FOR UPDATE&lt;/code&gt; (Pessimistic Locking)&lt;/h3&gt;
&lt;p&gt;Acquires a row-level write lock as part of the read. Other transactions that try to read the same row with &lt;code&gt;FOR UPDATE&lt;/code&gt; block until you commit.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;BEGIN&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; stock &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; products &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; sku &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;WIDGET&apos;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FOR&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; UPDATE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;  -- application logic decides what to write&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  UPDATE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; products &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; stock &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; stock &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; sku &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;WIDGET&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;COMMIT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use when you need to read, decide, and write atomically and the read must reflect the latest committed value, not a snapshot. Common in inventory deduction, ticket reservation, money transfer.&lt;/p&gt;
&lt;p&gt;Watch out: holding a row lock across an HTTP boundary or a slow operation pins the lock for the duration. A &lt;code&gt;SELECT … FOR UPDATE&lt;/code&gt; followed by a 2-second external API call followed by &lt;code&gt;COMMIT&lt;/code&gt; means every concurrent request for that row waits 2 seconds.&lt;/p&gt;
&lt;h3 id=&quot;atomic-updates&quot;&gt;Atomic Updates&lt;/h3&gt;
&lt;p&gt;When the new value is a pure function of the old one, skip the lock and let the database compute it:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;UPDATE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; products&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; stock &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; stock &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; sku &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;WIDGET&apos;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; stock &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Single statement, no read-modify-write race. The &lt;code&gt;AND stock &gt; 0&lt;/code&gt; predicate prevents negative stock without an extra check. The simplest correct solution to lost updates when applicable.&lt;/p&gt;
&lt;h3 id=&quot;optimistic-concurrency-control-version-columns&quot;&gt;Optimistic Concurrency Control (Version Columns)&lt;/h3&gt;
&lt;p&gt;Add a &lt;code&gt;version&lt;/code&gt; column. Every update increments it. Every update conditions the write on the version it last read:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; id, balance, &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; accounts &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 42&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;-- application: balance=100, version=7&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;UPDATE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; accounts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; balance &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 80&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 42&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; AND&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; version&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 7&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If another transaction wrote first, the row’s version is now 8 and your &lt;code&gt;WHERE version = 7&lt;/code&gt; matches zero rows. The application sees &lt;code&gt;rowcount = 0&lt;/code&gt; and retries the read-modify-write cycle.&lt;/p&gt;
&lt;p&gt;Pros: no blocking, no deadlocks, works across HTTP boundaries (the version travels in the request). Cons: requires retry logic, performs poorly under high contention.&lt;/p&gt;
&lt;p&gt;The decision between pessimistic and optimistic comes down to &lt;strong&gt;contention rate&lt;/strong&gt;. Rare contention → optimistic. Frequent contention → pessimistic.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;decision-tree&quot;&gt;Decision Tree&lt;/h2&gt;













































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Scenario&lt;/th&gt;&lt;th&gt;Reach for&lt;/th&gt;&lt;th&gt;Why&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Standard web app CRUD, dashboards, profile reads&lt;/td&gt;&lt;td&gt;&lt;code&gt;READ COMMITTED&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Default. Cheap. Anomalies are real but acceptable in this domain.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Multi-step report or invoice — query the same data multiple times in one transaction&lt;/td&gt;&lt;td&gt;&lt;code&gt;REPEATABLE READ&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Consistent snapshot. Avoids the price-changed-mid-transaction class of bug.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Concurrent decrement of a counter / stock / balance&lt;/td&gt;&lt;td&gt;Atomic &lt;code&gt;UPDATE ... SET x = x - 1&lt;/code&gt; at &lt;code&gt;READ COMMITTED&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Single statement, no race. Don’t reach for higher isolation.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Need to read, decide, then write atomically; long-lived contention expected&lt;/td&gt;&lt;td&gt;&lt;code&gt;SELECT … FOR UPDATE&lt;/code&gt; at &lt;code&gt;READ COMMITTED&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Pessimistic lock on the row. Easy mental model. Watch lock duration.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Same, but contention is rare and you can retry&lt;/td&gt;&lt;td&gt;Optimistic version column at &lt;code&gt;READ COMMITTED&lt;/code&gt;&lt;/td&gt;&lt;td&gt;No blocking, works across HTTP boundaries, just needs retry logic.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Multi-row invariant (“at least one doctor on call,” “no double-booking”)&lt;/td&gt;&lt;td&gt;&lt;code&gt;SERIALIZABLE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Only level that catches write skew. Implement retry on serialization failure.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Financial transfers, double-entry ledger&lt;/td&gt;&lt;td&gt;&lt;code&gt;SERIALIZABLE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;The lost-money class of bug. Worth the aborts.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The pattern: &lt;strong&gt;default to &lt;code&gt;READ COMMITTED&lt;/code&gt;, raise selectively where the workload demands it.&lt;/strong&gt; Most applications need higher isolation only on specific endpoints — not as a global setting.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;common-mistakes&quot;&gt;Common Mistakes&lt;/h2&gt;
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Treating the ORM default as the right answer.&lt;/strong&gt; Hibernate/JPA defaults to &lt;code&gt;REPEATABLE_READ&lt;/code&gt;, Rails ActiveRecord uses &lt;code&gt;READ COMMITTED&lt;/code&gt;, Django passes through to the DB default. Check what your stack is actually doing before assuming.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Setting &lt;code&gt;SERIALIZABLE&lt;/code&gt; globally as “safety.”&lt;/strong&gt; Most code paths don’t need it, and most application code doesn’t handle serialization-failure retries. The result is random &lt;code&gt;40001&lt;/code&gt; errors under load that look like flaky tests.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Using &lt;code&gt;SERIALIZABLE&lt;/code&gt; without retry logic.&lt;/strong&gt; SSI assumes the application retries aborted transactions. Without retry, &lt;code&gt;SERIALIZABLE&lt;/code&gt; is strictly worse than Repeatable Read.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Holding a transaction open across a network round-trip.&lt;/strong&gt; Every external API call, every queue write, every cross-service hop inside a &lt;code&gt;BEGIN … COMMIT&lt;/code&gt; extends lock duration. Open the transaction at the last possible moment, close it immediately.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Read-modify-write where atomic update would work.&lt;/strong&gt; &lt;code&gt;SELECT balance&lt;/code&gt; → decide → &lt;code&gt;UPDATE balance&lt;/code&gt; invites lost updates. Use &lt;code&gt;UPDATE … SET balance = balance + ?&lt;/code&gt; instead.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Assuming MySQL Repeatable Read prevents phantoms in plain &lt;code&gt;SELECT&lt;/code&gt;.&lt;/strong&gt; It does only for locking reads. Plain &lt;code&gt;SELECT&lt;/code&gt; uses snapshot reads.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Assuming Repeatable Read prevents write skew.&lt;/strong&gt; It doesn’t — that’s specifically what &lt;code&gt;SERIALIZABLE&lt;/code&gt; (or explicit row locking via &lt;code&gt;FOR UPDATE&lt;/code&gt;) is for.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Long-running transactions on a busy primary.&lt;/strong&gt; MVCC bloat: every transaction’s snapshot pins all row versions newer than the snapshot. A 10-minute transaction keeps 10 minutes of dead versions around, slowing every other query.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Mixing optimistic and pessimistic in the same flow.&lt;/strong&gt; Confusing to reason about. Pick one strategy per resource.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Trusting “Serializable” as a name.&lt;/strong&gt; Oracle’s &lt;code&gt;SERIALIZABLE&lt;/code&gt; is snapshot isolation. Always check your DB’s actual semantics.&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;strong&gt;Ignoring deadlocks.&lt;/strong&gt; Pessimistic locking on multiple rows in different orders deadlocks under concurrency. Standardize the lock order (e.g., always lock the smaller account ID first in a transfer).&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;closing&quot;&gt;Closing&lt;/h2&gt;
&lt;p&gt;Isolation level isn’t a “set and forget” knob. It’s a per-workload decision that interacts with how you structure your transactions, how long you hold them open, and what your application does when a commit fails. The teams that get this right are usually the ones who default to &lt;code&gt;READ COMMITTED&lt;/code&gt;, identify which specific transactions actually need stronger guarantees, raise those to &lt;code&gt;REPEATABLE READ&lt;/code&gt; or &lt;code&gt;SERIALIZABLE&lt;/code&gt;, and handle retries in code. The teams that get it wrong either set &lt;code&gt;SERIALIZABLE&lt;/code&gt; everywhere and wonder why their throughput collapsed, or stay on &lt;code&gt;READ COMMITTED&lt;/code&gt; and write &lt;code&gt;SELECT … FOR UPDATE&lt;/code&gt; everywhere as a substitute.&lt;/p&gt;
&lt;p&gt;Getting these wrong is how production databases produce corrupted data, double-bookings, billing discrepancies, and race conditions that only show up at 3 AM under peak load. Getting them right is mostly about understanding &lt;em&gt;which&lt;/em&gt; anomaly your code can encounter, choosing the cheapest level that prevents it, and writing the retry path for when the database asks you to.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;related-reading&quot;&gt;Related reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/database-normalization/&quot;&gt;Database Normalization&lt;/a&gt; — the schema-level rules transactions defend.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/db-storage-and-indexing/&quot;&gt;How Databases Actually Store and Find Your Data&lt;/a&gt; — what “a row” physically is, the substrate for everything above.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/postgres-indexing/&quot;&gt;PostgreSQL Indexing Deep Dive&lt;/a&gt; — including how &lt;code&gt;CREATE INDEX CONCURRENTLY&lt;/code&gt; interacts with isolation.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/postgres-replication/&quot;&gt;Database Replication&lt;/a&gt; — how isolation guarantees travel (or don’t) across replicas.&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Database Normalization: 1NF through 5NF Explained</title><link>https://abhimanyunagurkar.com/blog/database-normalization/</link><guid isPermaLink="true">https://abhimanyunagurkar.com/blog/database-normalization/</guid><description>A practical guide to database normalization — 1NF through 5NF, when to denormalize, and the pitfalls teams hit. With concrete data examples.</description><pubDate>Sun, 19 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Database normalization is the process of organizing tables to reduce redundancy and prevent data anomalies. Each “normal form” is a progressively stricter rule about how data should be structured. For each form, we’ll look at a table that violates it, explain exactly why, then show the corrected design with real data.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;first-normal-form-1nf&quot;&gt;First Normal Form (1NF)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The Rule:&lt;/strong&gt; Every column holds atomic (indivisible) values. No repeating groups. Every row is uniquely identifiable by a primary key. Column data types are consistent.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Violating Table — Insured Customer Family Data:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Imagine the columns repeating: &lt;code&gt;Child_1, Age_1, Child_2, Age_2, ...&lt;/code&gt; — the duplicate column names below render as a single header in markdown but represent the unbounded repeating-group violation.)&lt;/em&gt;&lt;/p&gt;













































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Customer Code&lt;/th&gt;&lt;th&gt;Customer Surname&lt;/th&gt;&lt;th&gt;Child&lt;/th&gt;&lt;th&gt;Age&lt;/th&gt;&lt;th&gt;Child&lt;/th&gt;&lt;th&gt;Age ···&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;DENT04&lt;/td&gt;&lt;td&gt;Denton&lt;/td&gt;&lt;td&gt;Billy&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Olivia&lt;/td&gt;&lt;td&gt;10&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;PARK31&lt;/td&gt;&lt;td&gt;Park&lt;/td&gt;&lt;td&gt;Justin&lt;/td&gt;&lt;td&gt;7&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;PARK31&lt;/td&gt;&lt;td&gt;Park&lt;/td&gt;&lt;td&gt;Phoebe&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;KELL17&lt;/td&gt;&lt;td&gt;Keller&lt;/td&gt;&lt;td&gt;Alice&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;Ivy&lt;/td&gt;&lt;td&gt;Newborn ···&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;This table violates 1NF in &lt;strong&gt;four separate ways&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Row order is meaningful&lt;/strong&gt; — the header says “from most-recently-entered (top) to least-recently-entered (bottom)”. Data meaning should never depend on row order.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inconsistent data types&lt;/strong&gt; — the &lt;code&gt;Age&lt;/code&gt; column holds integers in some rows (“10”) and strings in others (“Newborn”). A column must have one consistent type.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No primary key&lt;/strong&gt; — &lt;code&gt;Customer Code&lt;/code&gt; is not unique: PARK31 appears twice. Uniqueness is not being enforced.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Repeating groups&lt;/strong&gt; — &lt;code&gt;Child&lt;/code&gt; and &lt;code&gt;Age&lt;/code&gt; columns repeat indefinitely across the row. The number of children is unbounded, so there’s no way to design a fixed schema.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;The Fix — Two tables, both in 1NF (and well-normalized for this schema — we’ll see what 5NF actually requires further down):&lt;/strong&gt;&lt;/p&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Customer_Code&lt;/th&gt;&lt;th&gt;Customer_Surname&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;DENT04&lt;/td&gt;&lt;td&gt;Denton&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;PARK31&lt;/td&gt;&lt;td&gt;Park&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;KELL17&lt;/td&gt;&lt;td&gt;Keller&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;




































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Customer_Code&lt;/th&gt;&lt;th&gt;Child_Seq_No&lt;/th&gt;&lt;th&gt;Child_Name&lt;/th&gt;&lt;th&gt;Child_Age&lt;/th&gt;&lt;th&gt;Date_Recorded&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;PARK31&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Phoebe&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;2026-01-27&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;PARK31&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Justin&lt;/td&gt;&lt;td&gt;7&lt;/td&gt;&lt;td&gt;2026-01-28&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;DENT04&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Billy&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;2026-02-01&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;DENT04&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Olivia&lt;/td&gt;&lt;td&gt;10&lt;/td&gt;&lt;td&gt;2026-02-01&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;KELL17&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Ivy&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;2026-01-19&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;KELL17&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Alice&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;2026-01-19&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;KELL17&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Jonah&lt;/td&gt;&lt;td&gt;7&lt;/td&gt;&lt;td&gt;2026-01-19&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;KELL17&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;Billy&lt;/td&gt;&lt;td&gt;9&lt;/td&gt;&lt;td&gt;2026-01-19&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;Primary key of &lt;code&gt;Customer&lt;/code&gt; = &lt;code&gt;Customer_Code&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Primary key of &lt;code&gt;Customer_Dependent_Child&lt;/code&gt; = &lt;code&gt;{ Customer_Code, Child_Seq_No }&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Customer_Code&lt;/code&gt; on the child table is a foreign key to the &lt;code&gt;Customer&lt;/code&gt; table&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Date_Recorded&lt;/code&gt; replaces row ordering as the way to track recency&lt;/li&gt;
&lt;li&gt;In a real database, &lt;code&gt;Child_Age&lt;/code&gt; would be replaced with &lt;code&gt;Child_Birth_Date&lt;/code&gt; — age changes, birth dates don’t&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;a-quick-note-on-functional-dependencies&quot;&gt;A Quick Note on Functional Dependencies&lt;/h2&gt;
&lt;p&gt;Before 2NF, here’s the notation we’ll use throughout. A &lt;strong&gt;functional dependency&lt;/strong&gt; &lt;code&gt;X → Y&lt;/code&gt; means: “given &lt;code&gt;X&lt;/code&gt;, you can determine &lt;code&gt;Y&lt;/code&gt; uniquely.” If you know an &lt;code&gt;Employee_Code&lt;/code&gt;, you know exactly one &lt;code&gt;Employee_Surname&lt;/code&gt;. So &lt;code&gt;Employee_Code → Employee_Surname&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The normal forms are progressively stricter rules about which functional dependencies are allowed in a single relation. The mnemonic for 1NF/2NF/3NF is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Every non-key column depends on &lt;strong&gt;the key, the whole key, and nothing but the key.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;1NF&lt;/strong&gt; — every value is atomic; the table has &lt;em&gt;a&lt;/em&gt; key.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2NF&lt;/strong&gt; — non-key columns depend on the &lt;em&gt;whole&lt;/em&gt; key (no partial dependencies on part of a composite key).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3NF&lt;/strong&gt; — non-key columns depend on &lt;em&gt;nothing but&lt;/em&gt; the key (no transitive dependencies through other non-key columns).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;BCNF, 4NF, and 5NF generalize this further to handle edge cases. We’ll get to those.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;second-normal-form-2nf&quot;&gt;Second Normal Form (2NF)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The Rule:&lt;/strong&gt; Must be in 1NF. Every non-key column must depend on the &lt;strong&gt;entire&lt;/strong&gt; primary key — not just a part of it. This only applies when the primary key is composite (made up of more than one column).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Violating Table — Employee Working Days:&lt;/strong&gt;&lt;/p&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Employee_Code&lt;/th&gt;&lt;th&gt;Working_Day&lt;/th&gt;&lt;th&gt;Employee_Surname&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;WREN02&lt;/td&gt;&lt;td&gt;TUESDAY&lt;/td&gt;&lt;td&gt;Wren&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;WREN02&lt;/td&gt;&lt;td&gt;WEDNESDAY&lt;/td&gt;&lt;td&gt;Wren&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;WREN02&lt;/td&gt;&lt;td&gt;THURSDAY&lt;/td&gt;&lt;td&gt;Wren&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;MILL01&lt;/td&gt;&lt;td&gt;MONDAY&lt;/td&gt;&lt;td&gt;Miller&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;MILL01&lt;/td&gt;&lt;td&gt;TUESDAY&lt;/td&gt;&lt;td&gt;Miller&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The primary key is &lt;code&gt;{ Employee_Code, Working_Day }&lt;/code&gt;. But &lt;code&gt;Employee_Surname&lt;/code&gt; only depends on &lt;code&gt;Employee_Code&lt;/code&gt; — it tells us about the employee, not about which day they work. This is a &lt;strong&gt;partial dependency&lt;/strong&gt;: a non-key column depends on only part of the composite key.&lt;/p&gt;
&lt;p&gt;The result is obvious in the data: “Wren” is repeated three times and “Miller” twice. If the employee changes their surname, every row must be updated — miss one and the data becomes inconsistent.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Fix:&lt;/strong&gt;&lt;/p&gt;

















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Employee_Code&lt;/th&gt;&lt;th&gt;Employee_Surname&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;WREN02&lt;/td&gt;&lt;td&gt;Wren&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;MILL01&lt;/td&gt;&lt;td&gt;Miller&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Employee_Code&lt;/th&gt;&lt;th&gt;Working_Day&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;WREN02&lt;/td&gt;&lt;td&gt;TUESDAY&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;WREN02&lt;/td&gt;&lt;td&gt;WEDNESDAY&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;WREN02&lt;/td&gt;&lt;td&gt;THURSDAY&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;MILL01&lt;/td&gt;&lt;td&gt;MONDAY&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;MILL01&lt;/td&gt;&lt;td&gt;TUESDAY&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;Primary key of &lt;code&gt;Employee&lt;/code&gt; = &lt;code&gt;Employee_Code&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Primary key of &lt;code&gt;Employee_Working_Days&lt;/code&gt; = &lt;code&gt;{ Employee_Code, Working_Day }&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Employee_Code&lt;/code&gt; on &lt;code&gt;Employee_Working_Days&lt;/code&gt; is a foreign key to &lt;code&gt;Employee&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Surname is stored once — update it in one place, it’s consistent everywhere&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;third-normal-form-3nf&quot;&gt;Third Normal Form (3NF)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The Rule:&lt;/strong&gt; Must be in 2NF. No non-key column should depend on another non-key column. Every non-key attribute must depend on &lt;strong&gt;the key, the whole key, and nothing but the key&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Violating Table — Product:&lt;/strong&gt;&lt;/p&gt;









































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Product_ID&lt;/th&gt;&lt;th&gt;Product_Name&lt;/th&gt;&lt;th&gt;Product_Subcategory&lt;/th&gt;&lt;th&gt;Product_Category&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;103&lt;/td&gt;&lt;td&gt;400-Piece Autumn Foliage Jigsaw&lt;/td&gt;&lt;td&gt;JIGSAWS&lt;/td&gt;&lt;td&gt;PUZZLES&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;104&lt;/td&gt;&lt;td&gt;250-Piece Magic Bookshop Jigsaw&lt;/td&gt;&lt;td&gt;JIGSAWS&lt;/td&gt;&lt;td&gt;PUZZLES&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;105&lt;/td&gt;&lt;td&gt;Standard Rubik’s Cube&lt;/td&gt;&lt;td&gt;MECHANICAL-PUZZLES&lt;/td&gt;&lt;td&gt;PUZZLES&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;106&lt;/td&gt;&lt;td&gt;Kendrick Koala&lt;/td&gt;&lt;td&gt;CUDDLY-TOYS&lt;/td&gt;&lt;td&gt;TOYS&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;107&lt;/td&gt;&lt;td&gt;Adventurer Walkie Talkie Set&lt;/td&gt;&lt;td&gt;ELECTRONIC-TOYS&lt;/td&gt;&lt;td&gt;TOYS&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The primary key is &lt;code&gt;Product_ID&lt;/code&gt;. &lt;code&gt;Product_Category&lt;/code&gt; depends on &lt;code&gt;Product_ID&lt;/code&gt; only &lt;em&gt;transitively&lt;/em&gt; — through &lt;code&gt;Product_Subcategory&lt;/code&gt;. The real determinant is &lt;code&gt;Product_Subcategory&lt;/code&gt;, and &lt;code&gt;Product_Subcategory&lt;/code&gt; is not a candidate key of this table. This is a &lt;strong&gt;transitive dependency&lt;/strong&gt;: &lt;code&gt;Product_ID → Product_Subcategory → Product_Category&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The redundancy is visible: “PUZZLES” appears three times and “TOYS” twice. If we rename the “PUZZLES” category, we have to update multiple rows. Miss one, the data becomes contradictory.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Fix:&lt;/strong&gt;&lt;/p&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Product_ID&lt;/th&gt;&lt;th&gt;Product_Name&lt;/th&gt;&lt;th&gt;Product_Subcategory&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;103&lt;/td&gt;&lt;td&gt;400-Piece Autumn Foliage Jigsaw&lt;/td&gt;&lt;td&gt;JIGSAWS&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;104&lt;/td&gt;&lt;td&gt;250-Piece Magic Bookshop Jigsaw&lt;/td&gt;&lt;td&gt;JIGSAWS&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;105&lt;/td&gt;&lt;td&gt;Standard Rubik’s Cube&lt;/td&gt;&lt;td&gt;MECHANICAL-PUZZLES&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;106&lt;/td&gt;&lt;td&gt;Kendrick Koala&lt;/td&gt;&lt;td&gt;CUDDLY-TOYS&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;107&lt;/td&gt;&lt;td&gt;Adventurer Walkie Talkie Set&lt;/td&gt;&lt;td&gt;ELECTRONIC-TOYS&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Product_Subcategory&lt;/th&gt;&lt;th&gt;Product_Category&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;JIGSAWS&lt;/td&gt;&lt;td&gt;PUZZLES&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;MECHANICAL-PUZZLES&lt;/td&gt;&lt;td&gt;PUZZLES&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CUDDLY-TOYS&lt;/td&gt;&lt;td&gt;TOYS&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ELECTRONIC-TOYS&lt;/td&gt;&lt;td&gt;TOYS&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;Primary key of &lt;code&gt;Product&lt;/code&gt; = &lt;code&gt;Product_ID&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Primary key of &lt;code&gt;Product_Subcategory&lt;/code&gt; = &lt;code&gt;Product_Subcategory&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Product_Subcategory&lt;/code&gt; on &lt;code&gt;Product&lt;/code&gt; is a foreign key to &lt;code&gt;Product_Subcategory&lt;/code&gt; table&lt;/li&gt;
&lt;li&gt;Renaming “PUZZLES” to “BRAIN-GAMES” now requires updating exactly one row&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;3NF is the practical target for most production databases.&lt;/strong&gt; It eliminates the most common redundancy and anomaly problems without over-fragmenting the schema.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;boyce-codd-normal-form-bcnf&quot;&gt;Boyce-Codd Normal Form (BCNF)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The Rule:&lt;/strong&gt; Must be in 3NF. For every functional dependency &lt;code&gt;X → Y&lt;/code&gt;, &lt;code&gt;X&lt;/code&gt; must be a candidate key. Every determinant must be a superkey.&lt;/p&gt;
&lt;p&gt;BCNF is a stricter variant of 3NF that catches edge cases involving tables with &lt;strong&gt;multiple overlapping candidate keys&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Violating Table — Course Scheduling:&lt;/strong&gt;&lt;/p&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Teacher&lt;/th&gt;&lt;th&gt;Subject&lt;/th&gt;&lt;th&gt;Room&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Dr. Lee&lt;/td&gt;&lt;td&gt;Databases&lt;/td&gt;&lt;td&gt;Room 101&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Dr. Lee&lt;/td&gt;&lt;td&gt;Algorithms&lt;/td&gt;&lt;td&gt;Room 202&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Dr. Kim&lt;/td&gt;&lt;td&gt;Databases&lt;/td&gt;&lt;td&gt;Room 303&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Business rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Each teacher-room pairing has exactly one subject (so &lt;code&gt;{Teacher, Room} → Subject&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Each room hosts only one subject (so &lt;code&gt;Room → Subject&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Candidate keys: &lt;code&gt;{Teacher, Room}&lt;/code&gt;. Note that &lt;code&gt;{Teacher, Subject}&lt;/code&gt; is &lt;em&gt;not&lt;/em&gt; a candidate key — multiple rooms can host the same teacher/subject pair.&lt;/p&gt;
&lt;p&gt;But &lt;code&gt;Room → Subject&lt;/code&gt; is a valid functional dependency — and &lt;code&gt;Room&lt;/code&gt; alone is &lt;strong&gt;not&lt;/strong&gt; a candidate key. This violates BCNF. The consequence: if Room 101 is reassigned to “Algorithms”, you might update one row but leave the teacher’s schedule inconsistent.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Fix:&lt;/strong&gt;&lt;/p&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Room&lt;/th&gt;&lt;th&gt;Subject&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Room 101&lt;/td&gt;&lt;td&gt;Databases&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Room 202&lt;/td&gt;&lt;td&gt;Algorithms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Room 303&lt;/td&gt;&lt;td&gt;Databases&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Teacher&lt;/th&gt;&lt;th&gt;Room&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Dr. Lee&lt;/td&gt;&lt;td&gt;Room 101&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Dr. Lee&lt;/td&gt;&lt;td&gt;Room 202&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Dr. Kim&lt;/td&gt;&lt;td&gt;Room 303&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Every determinant is now a candidate key. The &lt;code&gt;Room → Subject&lt;/code&gt; dependency lives in its own table where &lt;code&gt;Room&lt;/code&gt; is the primary key.&lt;/p&gt;
&lt;p&gt;BCNF decomposition is &lt;strong&gt;not always dependency-preserving&lt;/strong&gt; — splitting &lt;code&gt;Room → Subject&lt;/code&gt; into its own table loses the ability to enforce &lt;code&gt;{Teacher, Room} → Subject&lt;/code&gt; with a simple foreign key. This is the classic BCNF tradeoff: stronger normalization, weaker constraint enforcement.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;fourth-normal-form-4nf&quot;&gt;Fourth Normal Form (4NF)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The Rule:&lt;/strong&gt; Must be in BCNF. For every non-trivial multi-valued dependency &lt;code&gt;X →→ Y&lt;/code&gt;, &lt;code&gt;X&lt;/code&gt; must be a superkey of the relation.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;multi-valued dependency&lt;/strong&gt; exists when one attribute independently determines a &lt;em&gt;set&lt;/em&gt; of values for two other attributes in the same table — and those two sets are unrelated to each other.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Violating Table — Course Assignments:&lt;/strong&gt;&lt;/p&gt;






























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Course&lt;/th&gt;&lt;th&gt;Textbook&lt;/th&gt;&lt;th&gt;Teacher&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Databases&lt;/td&gt;&lt;td&gt;SQL Mastery&lt;/td&gt;&lt;td&gt;Dr. Lee&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Databases&lt;/td&gt;&lt;td&gt;SQL Mastery&lt;/td&gt;&lt;td&gt;Dr. Kim&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Databases&lt;/td&gt;&lt;td&gt;DB Internals&lt;/td&gt;&lt;td&gt;Dr. Lee&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Databases&lt;/td&gt;&lt;td&gt;DB Internals&lt;/td&gt;&lt;td&gt;Dr. Kim&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;A course has multiple textbooks AND multiple teachers — independently. Any teacher can use any textbook. The table is forced to store every possible &lt;code&gt;(Textbook, Teacher)&lt;/code&gt; combination. Adding a new teacher requires adding one row per textbook. Adding a textbook requires adding one row per teacher. Miss one and the data is inconsistent.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Fix:&lt;/strong&gt;&lt;/p&gt;

















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Course&lt;/th&gt;&lt;th&gt;Textbook&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Databases&lt;/td&gt;&lt;td&gt;SQL Mastery&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Databases&lt;/td&gt;&lt;td&gt;DB Internals&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;

















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Course&lt;/th&gt;&lt;th&gt;Teacher&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Databases&lt;/td&gt;&lt;td&gt;Dr. Lee&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Databases&lt;/td&gt;&lt;td&gt;Dr. Kim&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Each independent multi-valued fact lives in its own table. Adding Dr. Park as a teacher is now one row — not one row per textbook.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;fifth-normal-form-5nf&quot;&gt;Fifth Normal Form (5NF)&lt;/h2&gt;
&lt;p&gt;5NF is rarely the deciding factor in practical schema design — most production databases stop at 3NF or BCNF. We cover it here because the underlying idea (avoiding fabricated tuples on rejoin) is genuinely useful even when you’re not formally proving 5NF compliance.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Rule:&lt;/strong&gt; Must be in 4NF. The table cannot be decomposed further without losing information. Eliminates &lt;strong&gt;join dependencies&lt;/strong&gt; that are not implied by candidate keys.&lt;/p&gt;
&lt;p&gt;5NF applies when the only lossless way to decompose a table is into three or more smaller tables. Any two-table split introduces spurious (incorrect) rows when rejoined.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Violating Table — Supplier / Product / Project:&lt;/strong&gt;&lt;/p&gt;






























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Supplier&lt;/th&gt;&lt;th&gt;Product&lt;/th&gt;&lt;th&gt;Project&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;TechCorp&lt;/td&gt;&lt;td&gt;Laptop&lt;/td&gt;&lt;td&gt;Apollo&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;TechCorp&lt;/td&gt;&lt;td&gt;Laptop&lt;/td&gt;&lt;td&gt;Hermes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;TechCorp&lt;/td&gt;&lt;td&gt;Monitor&lt;/td&gt;&lt;td&gt;Apollo&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GadgetCo&lt;/td&gt;&lt;td&gt;Keyboard&lt;/td&gt;&lt;td&gt;Apollo&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;The constraint that makes this 5NF-relevant:&lt;/strong&gt; the table is only valid if the following business rule holds — &lt;em&gt;if Supplier S sells Product P, AND Product P is used in Project J, AND Supplier S is engaged on Project J, then &lt;code&gt;(S, P, J)&lt;/code&gt; must appear in the table.&lt;/em&gt; In other words, the relation is the join of three binary relations: SuppliersProducts, ProductsProjects, and SuppliersProjects. Without that constraint, the table is just a normal ternary relationship and no decomposition would lose information.&lt;/p&gt;
&lt;p&gt;The rule: a &lt;code&gt;(Supplier, Product, Project)&lt;/code&gt; row is only valid if all three pairwise relationships independently hold — the supplier sells that product, the product is used in that project, and the supplier is engaged on that project. No two-way split can enforce this correctly without creating spurious combinations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Fix — three pairwise tables:&lt;/strong&gt;&lt;/p&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Supplier&lt;/th&gt;&lt;th&gt;Product&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;TechCorp&lt;/td&gt;&lt;td&gt;Laptop&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;TechCorp&lt;/td&gt;&lt;td&gt;Monitor&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GadgetCo&lt;/td&gt;&lt;td&gt;Keyboard&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Product&lt;/th&gt;&lt;th&gt;Project&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Laptop&lt;/td&gt;&lt;td&gt;Apollo&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Laptop&lt;/td&gt;&lt;td&gt;Hermes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Monitor&lt;/td&gt;&lt;td&gt;Apollo&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Keyboard&lt;/td&gt;&lt;td&gt;Apollo&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Supplier&lt;/th&gt;&lt;th&gt;Project&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;TechCorp&lt;/td&gt;&lt;td&gt;Apollo&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;TechCorp&lt;/td&gt;&lt;td&gt;Hermes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GadgetCo&lt;/td&gt;&lt;td&gt;Apollo&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The original table is reconstructed by joining all three. Any pair-wise decomposition would introduce rows that were never true.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why three tables, not two?&lt;/strong&gt; If we decomposed into just &lt;code&gt;Supplier_Product (S, P)&lt;/code&gt; and &lt;code&gt;Product_Project (P, J)&lt;/code&gt;, rejoining on &lt;code&gt;P&lt;/code&gt; would manufacture rows that never appeared in the original table. For example, if Supplier A sells the Keyboard and Project Apollo uses Keyboards, the join produces &lt;code&gt;(A, Keyboard, Apollo)&lt;/code&gt; — even if Supplier A is not actually engaged on Apollo. The third table &lt;code&gt;Supplier_Project (S, J)&lt;/code&gt; is exactly the constraint that prevents this fabrication: only &lt;code&gt;(S, P, J)&lt;/code&gt; triples that survive joining all three tables are valid.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-progression-at-a-glance&quot;&gt;The Progression at a Glance&lt;/h2&gt;
&lt;figure class=&quot;d2-diagram&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;
&lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; data-d2-version=&quot;v0.7.1&quot; preserveAspectRatio=&quot;xMinYMin meet&quot; viewBox=&quot;0 0 421 1350&quot;&gt;&lt;svg class=&quot;d2-466625062 d2-svg&quot; width=&quot;421&quot; height=&quot;1350&quot; viewBox=&quot;-25 -25 421 1350&quot;&gt;&lt;rect x=&quot;-25.000000&quot; y=&quot;-25.000000&quot; width=&quot;421.000000&quot; height=&quot;1350.000000&quot; rx=&quot;0.000000&quot; fill=&quot;#FFFFFF&quot; class=&quot;fill-N7&quot; stroke-width=&quot;0&quot;&gt;&lt;/rect&gt;&lt;style type=&quot;text/css&quot;&gt;
.d2-466625062 .text-bold {
	font-family: &quot;d2-466625062-font-bold&quot;;
}
@font-face {
	font-family: d2-466625062-font-bold;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}
.d2-466625062 .text-italic {
	font-family: &quot;d2-466625062-font-italic&quot;;
}
@font-face {
	font-family: d2-466625062-font-italic;
	src: url(&quot;data:application/font-woff;base64,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&quot;);
}&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-466625062 .fill-N1{fill:#0A0F25;}
		.d2-466625062 .fill-N2{fill:#676C7E;}
		.d2-466625062 .fill-N3{fill:#9499AB;}
		.d2-466625062 .fill-N4{fill:#CFD2DD;}
		.d2-466625062 .fill-N5{fill:#DEE1EB;}
		.d2-466625062 .fill-N6{fill:#EEF1F8;}
		.d2-466625062 .fill-N7{fill:#FFFFFF;}
		.d2-466625062 .fill-B1{fill:#0D32B2;}
		.d2-466625062 .fill-B2{fill:#0D32B2;}
		.d2-466625062 .fill-B3{fill:#E3E9FD;}
		.d2-466625062 .fill-B4{fill:#E3E9FD;}
		.d2-466625062 .fill-B5{fill:#EDF0FD;}
		.d2-466625062 .fill-B6{fill:#F7F8FE;}
		.d2-466625062 .fill-AA2{fill:#4A6FF3;}
		.d2-466625062 .fill-AA4{fill:#EDF0FD;}
		.d2-466625062 .fill-AA5{fill:#F7F8FE;}
		.d2-466625062 .fill-AB4{fill:#EDF0FD;}
		.d2-466625062 .fill-AB5{fill:#F7F8FE;}
		.d2-466625062 .stroke-N1{stroke:#0A0F25;}
		.d2-466625062 .stroke-N2{stroke:#676C7E;}
		.d2-466625062 .stroke-N3{stroke:#9499AB;}
		.d2-466625062 .stroke-N4{stroke:#CFD2DD;}
		.d2-466625062 .stroke-N5{stroke:#DEE1EB;}
		.d2-466625062 .stroke-N6{stroke:#EEF1F8;}
		.d2-466625062 .stroke-N7{stroke:#FFFFFF;}
		.d2-466625062 .stroke-B1{stroke:#0D32B2;}
		.d2-466625062 .stroke-B2{stroke:#0D32B2;}
		.d2-466625062 .stroke-B3{stroke:#E3E9FD;}
		.d2-466625062 .stroke-B4{stroke:#E3E9FD;}
		.d2-466625062 .stroke-B5{stroke:#EDF0FD;}
		.d2-466625062 .stroke-B6{stroke:#F7F8FE;}
		.d2-466625062 .stroke-AA2{stroke:#4A6FF3;}
		.d2-466625062 .stroke-AA4{stroke:#EDF0FD;}
		.d2-466625062 .stroke-AA5{stroke:#F7F8FE;}
		.d2-466625062 .stroke-AB4{stroke:#EDF0FD;}
		.d2-466625062 .stroke-AB5{stroke:#F7F8FE;}
		.d2-466625062 .background-color-N1{background-color:#0A0F25;}
		.d2-466625062 .background-color-N2{background-color:#676C7E;}
		.d2-466625062 .background-color-N3{background-color:#9499AB;}
		.d2-466625062 .background-color-N4{background-color:#CFD2DD;}
		.d2-466625062 .background-color-N5{background-color:#DEE1EB;}
		.d2-466625062 .background-color-N6{background-color:#EEF1F8;}
		.d2-466625062 .background-color-N7{background-color:#FFFFFF;}
		.d2-466625062 .background-color-B1{background-color:#0D32B2;}
		.d2-466625062 .background-color-B2{background-color:#0D32B2;}
		.d2-466625062 .background-color-B3{background-color:#E3E9FD;}
		.d2-466625062 .background-color-B4{background-color:#E3E9FD;}
		.d2-466625062 .background-color-B5{background-color:#EDF0FD;}
		.d2-466625062 .background-color-B6{background-color:#F7F8FE;}
		.d2-466625062 .background-color-AA2{background-color:#4A6FF3;}
		.d2-466625062 .background-color-AA4{background-color:#EDF0FD;}
		.d2-466625062 .background-color-AA5{background-color:#F7F8FE;}
		.d2-466625062 .background-color-AB4{background-color:#EDF0FD;}
		.d2-466625062 .background-color-AB5{background-color:#F7F8FE;}
		.d2-466625062 .color-N1{color:#0A0F25;}
		.d2-466625062 .color-N2{color:#676C7E;}
		.d2-466625062 .color-N3{color:#9499AB;}
		.d2-466625062 .color-N4{color:#CFD2DD;}
		.d2-466625062 .color-N5{color:#DEE1EB;}
		.d2-466625062 .color-N6{color:#EEF1F8;}
		.d2-466625062 .color-N7{color:#FFFFFF;}
		.d2-466625062 .color-B1{color:#0D32B2;}
		.d2-466625062 .color-B2{color:#0D32B2;}
		.d2-466625062 .color-B3{color:#E3E9FD;}
		.d2-466625062 .color-B4{color:#E3E9FD;}
		.d2-466625062 .color-B5{color:#EDF0FD;}
		.d2-466625062 .color-B6{color:#F7F8FE;}
		.d2-466625062 .color-AA2{color:#4A6FF3;}
		.d2-466625062 .color-AA4{color:#EDF0FD;}
		.d2-466625062 .color-AA5{color:#F7F8FE;}
		.d2-466625062 .color-AB4{color:#EDF0FD;}
		.d2-466625062 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-466625062);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-466625062);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-466625062);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-466625062);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-466625062);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-466625062);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-466625062);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-466625062);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-466625062);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-466625062);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-466625062);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-466625062);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-466625062);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-466625062);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-466625062);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-466625062);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-466625062);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-466625062);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}&lt;/style&gt;&lt;g class=&quot;VU5G&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;27.000000&quot; y=&quot;0.000000&quot; width=&quot;318.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;186.000000&quot; y=&quot;38.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;186.000000&quot; dy=&quot;0.000000&quot;&gt;Unnormalized&lt;/tspan&gt;&lt;tspan x=&quot;186.000000&quot; dy=&quot;18.500000&quot;&gt;Repeating groups · mixed types · no PK&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;TkYx&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;0.000000&quot; y=&quot;203.000000&quot; width=&quot;371.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;185.500000&quot; y=&quot;241.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;185.500000&quot; dy=&quot;0.000000&quot;&gt;1NF&lt;/tspan&gt;&lt;tspan x=&quot;185.500000&quot; dy=&quot;18.500000&quot;&gt;Atomic values · consistent types · unique rows&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;TkYy&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;13.000000&quot; y=&quot;406.000000&quot; width=&quot;345.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;185.500000&quot; y=&quot;444.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;185.500000&quot; dy=&quot;0.000000&quot;&gt;2NF&lt;/tspan&gt;&lt;tspan x=&quot;185.500000&quot; dy=&quot;18.500000&quot;&gt;No partial dependencies on composite key&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;TkYz&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;67.000000&quot; y=&quot;609.000000&quot; width=&quot;238.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;186.000000&quot; y=&quot;647.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;186.000000&quot; dy=&quot;0.000000&quot;&gt;3NF&lt;/tspan&gt;&lt;tspan x=&quot;186.000000&quot; dy=&quot;18.500000&quot;&gt;No transitive dependencies&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;QkNORg==&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;32.000000&quot; y=&quot;812.000000&quot; width=&quot;307.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;185.500000&quot; y=&quot;850.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;185.500000&quot; dy=&quot;0.000000&quot;&gt;BCNF&lt;/tspan&gt;&lt;tspan x=&quot;185.500000&quot; dy=&quot;18.500000&quot;&gt;Every determinant is a candidate key&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;TkY0&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;9.000000&quot; y=&quot;1015.000000&quot; width=&quot;354.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;186.000000&quot; y=&quot;1053.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;186.000000&quot; dy=&quot;0.000000&quot;&gt;4NF&lt;/tspan&gt;&lt;tspan x=&quot;186.000000&quot; dy=&quot;18.500000&quot;&gt;No independent multi-valued dependencies&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;TkY1&quot;&gt;&lt;g class=&quot;shape&quot;&gt;&lt;rect x=&quot;5.000000&quot; y=&quot;1218.000000&quot; width=&quot;362.000000&quot; height=&quot;82.000000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;#F7F8FE&quot; class=&quot;stroke-B1 fill-B6&quot; style=&quot;stroke-width:2;&quot;&gt;&lt;/rect&gt;&lt;/g&gt;&lt;text x=&quot;186.000000&quot; y=&quot;1256.500000&quot; fill=&quot;#0A0F25&quot; class=&quot;text-bold fill-N1&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;&lt;tspan x=&quot;186.000000&quot; dy=&quot;0.000000&quot;&gt;5NF&lt;/tspan&gt;&lt;tspan x=&quot;186.000000&quot; dy=&quot;18.500000&quot;&gt;No join dependencies beyond candidate keys&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KFVORiAtJmd0OyBORjEpWzBd&quot;&gt;&lt;marker id=&quot;mk-d2-466625062-3488378134&quot; markerWidth=&quot;10.000000&quot; markerHeight=&quot;12.000000&quot; refX=&quot;7.000000&quot; refY=&quot;6.000000&quot; viewBox=&quot;0.000000 0.000000 10.000000 12.000000&quot; orient=&quot;auto&quot; markerUnits=&quot;userSpaceOnUse&quot;&gt; &lt;polygon points=&quot;0.000000,0.000000 10.000000,6.000000 0.000000,12.000000&quot; fill=&quot;#0D32B2&quot; class=&quot;connection fill-B1&quot; stroke-width=&quot;2&quot;&gt;&lt;/polygon&gt; &lt;/marker&gt;&lt;path d=&quot;M 185.500000 83.500000 C 185.500000 130.300003 185.500000 154.699997 185.500000 199.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-466625062-3488378134)&quot; mask=&quot;url(#d2-466625062)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;186.000000&quot; y=&quot;148.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;atomic values + primary key&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KE5GMSAtJmd0OyBORjIpWzBd&quot;&gt;&lt;path d=&quot;M 185.500000 286.500000 C 185.500000 333.299988 185.500000 357.700012 185.500000 402.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-466625062-3488378134)&quot; mask=&quot;url(#d2-466625062)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;185.500000&quot; y=&quot;351.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;remove partial dependencies&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KE5GMiAtJmd0OyBORjMpWzBd&quot;&gt;&lt;path d=&quot;M 185.500000 489.500000 C 185.500000 536.299988 185.500000 560.700012 185.500000 605.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-466625062-3488378134)&quot; mask=&quot;url(#d2-466625062)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;185.500000&quot; y=&quot;554.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;remove transitive dependencies&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KE5GMyAtJmd0OyBCQ05GKVswXQ==&quot;&gt;&lt;path d=&quot;M 185.500000 692.500000 C 185.500000 739.299988 185.500000 763.700012 185.500000 808.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-466625062-3488378134)&quot; mask=&quot;url(#d2-466625062)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;185.500000&quot; y=&quot;757.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;every determinant → superkey&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KEJDTkYgLSZndDsgTkY0KVswXQ==&quot;&gt;&lt;path d=&quot;M 185.500000 895.500000 C 185.500000 942.299988 185.500000 966.700012 185.500000 1011.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-466625062-3488378134)&quot; mask=&quot;url(#d2-466625062)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;186.000000&quot; y=&quot;960.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;split independent multi-valued facts&lt;/text&gt;&lt;/g&gt;&lt;g class=&quot;KE5GNCAtJmd0OyBORjUpWzBd&quot;&gt;&lt;path d=&quot;M 185.500000 1098.500000 C 185.500000 1145.300049 185.500000 1169.699951 185.500000 1214.500000&quot; stroke=&quot;#0D32B2&quot; fill=&quot;none&quot; class=&quot;connection stroke-B1&quot; style=&quot;stroke-width:2;&quot; marker-end=&quot;url(#mk-d2-466625062-3488378134)&quot; mask=&quot;url(#d2-466625062)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;185.500000&quot; y=&quot;1163.000000&quot; fill=&quot;#676C7E&quot; class=&quot;text-italic fill-N2&quot; style=&quot;text-anchor:middle;font-size:16px&quot;&gt;remove join dependencies&lt;/text&gt;&lt;/g&gt;&lt;mask id=&quot;d2-466625062&quot; maskUnits=&quot;userSpaceOnUse&quot; x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;421&quot; height=&quot;1350&quot;&gt;
&lt;rect x=&quot;-25&quot; y=&quot;-25&quot; width=&quot;421&quot; height=&quot;1350&quot; fill=&quot;white&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;92.000000&quot; y=&quot;132.000000&quot; width=&quot;188&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;88.000000&quot; y=&quot;335.000000&quot; width=&quot;195&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;79.000000&quot; y=&quot;538.000000&quot; width=&quot;213&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;85.000000&quot; y=&quot;741.000000&quot; width=&quot;201&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;65.000000&quot; y=&quot;944.000000&quot; width=&quot;242&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;rect x=&quot;98.000000&quot; y=&quot;1147.000000&quot; width=&quot;175&quot; height=&quot;21&quot; fill=&quot;black&quot;&gt;&lt;/rect&gt;
&lt;/mask&gt;&lt;/svg&gt;&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;3NF / BCNF is the right target for most production systems.&lt;/strong&gt; Go further only when you have genuinely independent multi-valued facts (4NF) or complex three-way join dependencies (5NF).&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;when-to-denormalize&quot;&gt;When to Denormalize&lt;/h2&gt;
&lt;p&gt;Normalization is the right starting point — not always the ending point. Intentional redundancy is valid when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Read performance is critical&lt;/strong&gt; — heavily joined queries across many normalized tables are expensive. A materialized view or denormalized reporting table can dramatically speed up reads.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You’re building a data warehouse&lt;/strong&gt; — OLAP workloads favor wide flat tables (star/snowflake schemas) over normalized OLTP schemas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The data rarely changes&lt;/strong&gt; — if a field updates once a year, the update anomaly risk is low.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A query is too hot to afford joins&lt;/strong&gt; — on high-throughput endpoints, a cache field with an explicit refresh strategy can be worth the complexity.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Normalize first, denormalize deliberately.&lt;/strong&gt; Start clean, measure where bottlenecks actually are, and introduce redundancy with intention — not by accident.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;pitfalls-and-common-mistakes&quot;&gt;Pitfalls and Common Mistakes&lt;/h2&gt;
&lt;p&gt;The rules above are clear, but applying them in practice is where teams get into trouble. The recurring patterns worth watching for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Confusing 3NF with BCNF.&lt;/strong&gt; They sound interchangeable but aren’t. A relation can be in 3NF and still violate BCNF if a non-key attribute determines another candidate-key attribute. Check every functional dependency — not just the ones from the primary key.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Treating 4NF and 5NF as required.&lt;/strong&gt; They apply only when independent multi-valued facts (4NF) or three-way join dependencies (5NF) actually exist in your data. Most production schemas don’t hit either situation. Don’t decompose chasing a textbook target you don’t have.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Over-normalizing read-mostly schemas.&lt;/strong&gt; Splitting tables to satisfy 3NF only pays off if updates happen. A table where rows are written once and never modified rarely benefits from being split into three with foreign keys — you’re paying join cost for no anomaly-prevention upside.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mistaking “atomic” for “small.”&lt;/strong&gt; 1NF demands no repeating groups, not “no complex values.” A JSONB document, a PostGIS geometry, or an array column is 1NF-compliant if treated as a single indivisible value. Don’t split data that the application always reads and writes as a unit.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dropping foreign keys “for performance.”&lt;/strong&gt; Foreign keys cost very little on modern Postgres and are the only mechanism that guarantees the referential integrity normalization assumes. Disabling them turns “guaranteed valid” into “valid as long as no bug ever ships.”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Storing derived values that violate 3NF.&lt;/strong&gt; A row holding &lt;code&gt;unit_price&lt;/code&gt;, &lt;code&gt;quantity&lt;/code&gt;, &lt;em&gt;and&lt;/em&gt; &lt;code&gt;total_price&lt;/code&gt; creates a transitive dependency (&lt;code&gt;total_price&lt;/code&gt; is derivable from the other two). Either compute it on read or accept the redundancy with an explicit refresh strategy and write the trigger / view that keeps it consistent.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adding nullable “extension” columns instead of normalizing.&lt;/strong&gt; Adding &lt;code&gt;secondary_email&lt;/code&gt;, &lt;code&gt;tertiary_email&lt;/code&gt;, &lt;code&gt;home_phone&lt;/code&gt;, &lt;code&gt;work_phone&lt;/code&gt; to a &lt;code&gt;users&lt;/code&gt; table — most of them null for most users — is a repeating group disguised as separate columns. The right move is a &lt;code&gt;user_contact_methods&lt;/code&gt; child table.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Premature normalization before knowing the access patterns.&lt;/strong&gt; Splitting a domain into eight tables before you know how the application queries it produces a schema optimized for nothing. Sketch the read paths first; let them inform the table boundaries.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Forgetting that BCNF decomposition isn’t always dependency-preserving.&lt;/strong&gt; Decomposing to satisfy BCNF can scatter a multi-attribute functional dependency across two tables in a way that makes it un-enforceable with a simple FK. Decide explicitly whether you’d rather lose the BCNF guarantee or the dependency-preservation guarantee — there’s no fully correct answer.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Using surrogate keys to “skip” normalization.&lt;/strong&gt; Adding an &lt;code&gt;id BIGSERIAL&lt;/code&gt; to a table doesn’t make it normalized — it just gives the existing duplicates a new column. Normalize against the real candidate keys; add surrogate IDs as an implementation detail for foreign-key ergonomics.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ignoring functional dependencies in legacy schemas.&lt;/strong&gt; When refactoring a denormalized table, list every &lt;code&gt;X → Y&lt;/code&gt; you can identify in the data before designing the new shape. The dependencies tell you where the tables want to split — guessing produces a schema that fights you at the next migration.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;related-reading&quot;&gt;Related reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/acid-properties-and-isolation-levels/&quot;&gt;ACID and Isolation Levels&lt;/a&gt; — what transactions defend the schema you’ve now normalized.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/db-storage-and-indexing/&quot;&gt;How Databases Actually Store and Find Your Data&lt;/a&gt; — what your normalized rows physically become.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/postgres-explain/&quot;&gt;Reading PostgreSQL EXPLAIN Output&lt;/a&gt; — how a normalized schema’s joins translate to plan nodes.&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item></channel></rss>