Postgres uses a specific brand of MVCC (<a href="https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Multiversion_concurrency_control" rel="nofollow">https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Multiversion_concurrency_contr...</a>) where multiple versions of a row are stored in the heap.  That&#x27;s why there&#x27;s vacuuming to remove those.<p>To avoid having to vacuum whole relations all the time there&#x27;s the &quot;visibility map&quot;, which keeps track of which blocks have no dirty rows; so they can be skipped during vacuum.<p>To understand which versions are visible postgres stores transaction-ids in the row headers; these are four byte wide. On systems with significant throughput, those don&#x27;t last very long.  So every now and then there&#x27;s anti-wraparound vacuums; which replaces xids which are about to become &quot;too old&quot; with a special marker (&quot;frozen&quot;).<p>The problem &lt; 9.6 is that these anti-wraparound vacuums have to scan the whole table, thereby are a lot more expensive. These happen every 200 million xids by default (write transactions and&#x2F;or savepoints), configurable up to ~2 billion.  With the freeze map, that doesn&#x27;t have to happen, only non-frozen pages have to be re-scanned.